mirror of https://github.com/OpenIPC/firmware.git
				
				
				
			
		
			
				
	
	
		
			354 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Diff
		
	
	
			
		
		
	
	
			354 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Diff
		
	
	
| diff -urn -- a/miscutils/rng_fips.h b/miscutils/rng_fips.h
 | |
| --- a/miscutils/rng_fips.h	1970-01-01 00:00:00.000000000 +0000
 | |
| +++ b/miscutils/rng_fips.h	2008-08-17 13:28:27.000000000 +0000
 | |
| @@ -0,0 +1,152 @@
 | |
| +/* vi: set sw=4 ts=4: */
 | |
| +/* rng_fips.h
 | |
| + *
 | |
| + * Ported to busybox by Malek Degachi
 | |
| + *
 | |
| + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
 | |
| + */
 | |
| +
 | |
| +#ifndef _RNG_FIPS_H
 | |
| +#define _RNG_FIPS_H
 | |
| +
 | |
| +#include "libbb.h"
 | |
| +
 | |
| +/**********************************************
 | |
| + * FIPS part
 | |
| + *********************************************/
 | |
| +
 | |
| +/*  Size of a FIPS test buffer, do not change this */
 | |
| +#define FIPS_RNG_BUFFER_SIZE 2500
 | |
| +
 | |
| +/* Context for running FIPS tests */
 | |
| +typedef struct {
 | |
| +	int poker[16];
 | |
| +	int runs[12];
 | |
| +	int ones;
 | |
| +	int rlength;
 | |
| +	int current_bit;
 | |
| +	int last_bit;
 | |
| +	int longrun;
 | |
| +	unsigned int last32;
 | |
| +} fips_ctx_t;
 | |
| +
 | |
| +/*
 | |
| + * Return values for fips_run_rng_test. These values are OR'ed together
 | |
| + * for all tests that failed.
 | |
| + */
 | |
| +#define FIPS_RNG_MONOBIT	0x0001 /* FIPS 140-2 2001-10-10 monobit */
 | |
| +#define FIPS_RNG_POKER		0x0002 /* FIPS 140-2 2001-10-10 poker */
 | |
| +#define FIPS_RNG_RUNS		0x0004 /* FIPS 140-2 2001-10-10 runs */
 | |
| +#define FIPS_RNG_LONGRUN	0x0008 /* FIPS 140-2 2001-10-10 long run */
 | |
| +#define FIPS_RNG_CONTINUOUS_RUN 0x0010 /* FIPS 140-2 continuous run */
 | |
| +
 | |
| +/*
 | |
| + * fips_test_store - store 8 bits of entropy in FIPS
 | |
| + * 			 internal test data pool
 | |
| + */
 | |
| +static void fips_test_store(fips_ctx_t *ctx, unsigned int rng_data)
 | |
| +{
 | |
| +	int j;
 | |
| +
 | |
| +	ctx->poker[rng_data >> 4]++;
 | |
| +	ctx->poker[rng_data & 15]++;
 | |
| +
 | |
| +	/* Note in the loop below rlength is always one less than the actual
 | |
| +	   run length. This makes things easier. */
 | |
| +	for (j = 7; j >= 0; j--) {
 | |
| +		ctx->ones += ctx->current_bit = ((rng_data >> j) & 1);
 | |
| +		if (ctx->current_bit != ctx->last_bit) {
 | |
| +			/* If runlength is 1-6 count it in correct bucket. 0's go in
 | |
| +			   runs[0-5] 1's go in runs[6-11] hence the 6*current_bit below */
 | |
| +			if (ctx->rlength < 5) {
 | |
| +				ctx->runs[ctx->rlength +
 | |
| +				     (6 * ctx->current_bit)]++;
 | |
| +			} else {
 | |
| +				ctx->runs[5 + (6 * ctx->current_bit)]++;
 | |
| +			}
 | |
| +
 | |
| +			/* Check if we just failed longrun test */
 | |
| +			if (ctx->rlength >= 25)
 | |
| +				ctx->longrun = 1;
 | |
| +			ctx->rlength = 0;
 | |
| +			/* flip the current run type */
 | |
| +			ctx->last_bit = ctx->current_bit;
 | |
| +		} else {
 | |
| +			ctx->rlength++;
 | |
| +		}
 | |
| +	}
 | |
| +}
 | |
| +
 | |
| +static int fips_run_rng_test(fips_ctx_t *ctx, const void *buf)
 | |
| +{
 | |
| +	int i, j;
 | |
| +	int rng_test = 0;
 | |
| +	unsigned char *rngdatabuf;
 | |
| +
 | |
| +	if (!ctx) return -1;
 | |
| +	if (!buf) return -1;
 | |
| +	rngdatabuf = (unsigned char *)buf;
 | |
| +
 | |
| +	for (i=0; i<FIPS_RNG_BUFFER_SIZE; i += 4) {
 | |
| +		int new32 = rngdatabuf[i] | 
 | |
| +			    ( rngdatabuf[i+1] << 8 ) | 
 | |
| +			    ( rngdatabuf[i+2] << 16 ) | 
 | |
| +			    ( rngdatabuf[i+3] << 24 );
 | |
| +		if (new32 == ctx->last32) rng_test |= FIPS_RNG_CONTINUOUS_RUN;
 | |
| +		ctx->last32 = new32;
 | |
| +		fips_test_store(ctx, rngdatabuf[i]);
 | |
| +		fips_test_store(ctx, rngdatabuf[i+1]);
 | |
| +		fips_test_store(ctx, rngdatabuf[i+2]);
 | |
| +		fips_test_store(ctx, rngdatabuf[i+3]);
 | |
| +	}
 | |
| +
 | |
| +	/* add in the last (possibly incomplete) run */
 | |
| +	if (ctx->rlength < 5)
 | |
| +		ctx->runs[ctx->rlength + (6 * ctx->current_bit)]++;
 | |
| +	else {
 | |
| +		ctx->runs[5 + (6 * ctx->current_bit)]++;
 | |
| +		if (ctx->rlength >= 25)
 | |
| +			rng_test |= FIPS_RNG_LONGRUN;
 | |
| +	}
 | |
| +	
 | |
| +	if (ctx->longrun) {
 | |
| +		rng_test |= FIPS_RNG_LONGRUN;
 | |
| +		ctx->longrun = 0;
 | |
| +	}
 | |
| +
 | |
| +	/* Ones test */
 | |
| +	if ((ctx->ones >= 10275) || (ctx->ones <= 9725))
 | |
| +		rng_test |= FIPS_RNG_MONOBIT;
 | |
| +	/* Poker calcs */
 | |
| +	for (i = 0, j = 0; i < 16; i++)
 | |
| +		j += ctx->poker[i] * ctx->poker[i];
 | |
| +	/* 16/5000*1563176-5000 = 2.1632  */
 | |
| +	/* 16/5000*1576928-5000 = 46.1696 */
 | |
| +	if ((j > 1576928) || (j < 1563176))
 | |
| +		rng_test |= FIPS_RNG_POKER;
 | |
| +
 | |
| +	if ((ctx->runs[0] < 2315) || (ctx->runs[0] > 2685) ||
 | |
| +	    (ctx->runs[1] < 1114) || (ctx->runs[1] > 1386) ||
 | |
| +	    (ctx->runs[2] < 527) || (ctx->runs[2] > 723) ||
 | |
| +	    (ctx->runs[3] < 240) || (ctx->runs[3] > 384) ||
 | |
| +	    (ctx->runs[4] < 103) || (ctx->runs[4] > 209) ||
 | |
| +	    (ctx->runs[5] < 103) || (ctx->runs[5] > 209) ||
 | |
| +	    (ctx->runs[6] < 2315) || (ctx->runs[6] > 2685) ||
 | |
| +	    (ctx->runs[7] < 1114) || (ctx->runs[7] > 1386) ||
 | |
| +	    (ctx->runs[8] < 527) || (ctx->runs[8] > 723) ||
 | |
| +	    (ctx->runs[9] < 240) || (ctx->runs[9] > 384) ||
 | |
| +	    (ctx->runs[10] < 103) || (ctx->runs[10] > 209) ||
 | |
| +	    (ctx->runs[11] < 103) || (ctx->runs[11] > 209)) {
 | |
| +		rng_test |= FIPS_RNG_RUNS;
 | |
| +	}
 | |
| +	
 | |
| +	/* finally, clear out FIPS variables for start of next run */
 | |
| +	memset(ctx->poker, 0, sizeof (ctx->poker));
 | |
| +	memset(ctx->runs, 0, sizeof (ctx->runs));
 | |
| +	ctx->ones = 0;
 | |
| +	ctx->rlength = -1;
 | |
| +	ctx->current_bit = 0;
 | |
| +
 | |
| +	return rng_test;
 | |
| +}
 | |
| +#endif /* _RNG_FIPS_H */
 | |
| diff -urn -- a/miscutils/rngd.c b/miscutils/rngd.c
 | |
| --- a/miscutils/rngd.c	2021-04-14 10:06:59.131381906 +0300
 | |
| +++ b/miscutils/rngd.c	2021-04-14 10:04:59.785401231 +0300
 | |
| @@ -0,0 +1,193 @@
 | |
| +/* vi: set sw=4 ts=4: */
 | |
| +/*
 | |
| + * rngd implementation for busybox
 | |
| + *
 | |
| + * Ported to busybox by Malek Degachi
 | |
| + *
 | |
| + * Licensed under GPLv2 or later, see file License in this tarball for details.
 | |
| + *
 | |
| + */
 | |
| +
 | |
| +//config:config RNGD
 | |
| +//config:	bool "rngd"
 | |
| +//config:	default n
 | |
| +//config:	help
 | |
| +//config:	Hardware random number generation daemon.
 | |
| +//config:config FEATURE_RNGD_LONG_OPTIONS
 | |
| +//config:	bool "Enable long options"
 | |
| +//config:	default n
 | |
| +//config:	depends on RNGD && GETOPT_LONG
 | |
| +//config:	help
 | |
| +//config:	Support long options for the rngd applet.
 | |
| +
 | |
| +//applet:IF_RNGD(APPLET(rngd, BB_DIR_USR_SBIN, BB_SUID_DROP))
 | |
| +
 | |
| +//kbuild:lib-$(CONFIG_RNGD) += rngd.o
 | |
| +
 | |
| +//usage:#define rngd_trivial_usage
 | |
| +//usage:       "[-bf] [-o random file] [-r rng file] [-s step] [-t nnn] [-W n]"
 | |
| +//usage:#define rngd_full_usage "\n\n"
 | |
| +//usage:       "Check and feed random data from hardware device to kernel entropy pool.\n"
 | |
| +//usage:      "\nOptions:"
 | |
| +//usage:     "\n	-b,--background		Become a daemon (default)"
 | |
| +//usage:     "\n	-f,--foreground		Do not fork and become a daemon"
 | |
| +//usage:     "\n	-o,--rng-device=file	Kernel device used for random number output"
 | |
| +//usage:     "\n				(default: /dev/random)"
 | |
| +//usage:     "\n	-r,--random-step=nnn	Kernel device used for random number input"
 | |
| +//usage:     "\n				(default: /dev/hw_random)"
 | |
| +//usage:     "\n	-s,--random-step=nnn	Number of bytes written to random-device at a time"
 | |
| +//usage:     "\n				(default: 64)"
 | |
| +//usage:     "\n	-t,--timeout=nnn	Interval written to random-device when the entropy"
 | |
| +//usage:     "\n				pool is full, in seconds (default: 60)"
 | |
| +//usage:     "\n	-W,--fill-watermark=n	Do not stop feeding entropy to random-device until"
 | |
| +//usage:     "\n				at least n bits of entropy are available in the"
 | |
| +//usage:     "\n				pool (default: 2048), 0 <= n <= 4096"
 | |
| +
 | |
| +
 | |
| +#include "libbb.h"
 | |
| +#include "rng_fips.h"
 | |
| +#include <syslog.h>
 | |
| +
 | |
| +#ifndef __u32
 | |
| +typedef unsigned int __u32;
 | |
| +#endif
 | |
| +#include <linux/random.h>	/* struct rand_pool_info, RNDADDENTROPY and RNDGETENTCNT */
 | |
| +
 | |
| +enum {
 | |
| +	RNG_b	= (1 << 0),
 | |
| +	RNG_f	= (1 << 1),
 | |
| +	RNG_o	= (1 << 2),
 | |
| +	RNG_r	= (1 << 3),
 | |
| +	RNG_s	= (1 << 4),
 | |
| +	RNG_t	= (1 << 5),
 | |
| +	RNG_W	= (1 << 6),
 | |
| +};
 | |
| +
 | |
| +static void random_add_entropy(int random_fd, void *buf, size_t size)
 | |
| +{
 | |
| +	struct rand_pool_info *entropy;
 | |
| +
 | |
| +	entropy = xmalloc(sizeof(struct rand_pool_info) + size);
 | |
| +
 | |
| +	entropy->entropy_count = size * 8;
 | |
| +	entropy->buf_size = size;
 | |
| +	memcpy(entropy->buf, buf, size);
 | |
| +
 | |
| +	ioctl_or_perror_and_die(random_fd, RNDADDENTROPY, entropy, "RNDADDENTROPY failed: %s\n",
 | |
| +			strerror(errno));
 | |
| +}
 | |
| +
 | |
| +static void random_sleep(int random_fd, double timeout, unsigned fill_watermark)
 | |
| +{
 | |
| +	int ent_count;
 | |
| +	struct pollfd pfd[1];
 | |
| +
 | |
| +	pfd[0].fd = random_fd;
 | |
| +	pfd[0].events = POLLOUT;
 | |
| +
 | |
| +	ioctl_or_perror_and_die(random_fd, RNDGETENTCNT, &ent_count, "RNDGETENTCNT failed: %s\n",
 | |
| +			strerror(errno));
 | |
| +	if (ent_count < fill_watermark) return;
 | |
| +	
 | |
| +	safe_poll(pfd, 1, 1000.0 * timeout);
 | |
| +}
 | |
| +
 | |
| +/* Initialize entropy source */
 | |
| +static int discard_initial_data(int rng_fd)
 | |
| +{
 | |
| +	/* Trash 32 bits of what is probably stale (non-random)
 | |
| +	 * initial state from the RNG.  For Intel's, 8 bits would
 | |
| +	 * be enough, but since AMD's generates 32 bits at a time...
 | |
| +	 *
 | |
| +	 * The kernel drivers should be doing this at device powerup,
 | |
| +	 * but at least up to 2.4.24, it doesn't. */
 | |
| +	unsigned char tempbuf[4];
 | |
| +
 | |
| +	xread(rng_fd, tempbuf, sizeof tempbuf);
 | |
| +
 | |
| +	/* Return 32 bits of bootstrap data */
 | |
| +	xread(rng_fd, tempbuf, sizeof tempbuf);
 | |
| +
 | |
| +	return tempbuf[0] | (tempbuf[1] << 8) | 
 | |
| +		(tempbuf[2] << 16) | (tempbuf[3] << 24);
 | |
| +}
 | |
| +
 | |
| +
 | |
| +#if ENABLE_FEATURE_RNGD_LONG_OPTIONS
 | |
| +static const char rngd_longopts[] ALIGN1 =
 | |
| +	"background\0"		No_argument		"b"
 | |
| +	"foreground\0"		No_argument		"f"
 | |
| +	"random-device\0"	Required_argument	"o"
 | |
| +	"rng-device\0"		Required_argument	"r"
 | |
| +	"random-step\0"		Required_argument	"s"
 | |
| +	"timeout\0"		Required_argument	"t"
 | |
| +	"fill-watermark\0"	Required_argument	"W"
 | |
| +	;
 | |
| +#endif
 | |
| +
 | |
| +int rngd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 | |
| +int rngd_main(int argc UNUSED_PARAM, char **argv)
 | |
| +{
 | |
| +	const char *random_name = "/dev/random";
 | |
| +	const char *rng_name = "/dev/hw_random";
 | |
| +	int random_step = 64;
 | |
| +	unsigned fill_watermark;
 | |
| +	double poll_timeout = 60;
 | |
| +
 | |
| +	const char *watermark = "2048";
 | |
| +	static int rng_fd;
 | |
| +	static int random_fd;
 | |
| +
 | |
| +	unsigned char buf[FIPS_RNG_BUFFER_SIZE];
 | |
| +	unsigned char *p;
 | |
| +	int fips;
 | |
| +	fips_ctx_t *fipsctx;
 | |
| +
 | |
| +#if ENABLE_FEATURE_RNGD_LONG_OPTIONS
 | |
| +	applet_long_options = rngd_longopts;
 | |
| +#endif
 | |
| +
 | |
| +
 | |
| +	getopt32(argv, "bfo:r:s:t:W:", &random_name, &rng_name, &random_step, &poll_timeout, &watermark);
 | |
| +	argv += optind;
 | |
| +
 | |
| +	fill_watermark = xatou_range(watermark, 0, 4096);
 | |
| +
 | |
| +	/* Init entropy source, and open hardware RNG device */
 | |
| +	rng_fd = xopen(rng_name, O_RDONLY);
 | |
| +
 | |
| +	/* Bootstrap FIPS tests */
 | |
| +	fipsctx = (fips_ctx_t *) xzalloc(sizeof(fips_ctx_t));
 | |
| +	fipsctx->rlength = -1;
 | |
| +	fipsctx->last32 = discard_initial_data(rng_fd);
 | |
| +
 | |
| +	/* Init entropy sink and open random device */
 | |
| +	random_fd = xopen(random_name, O_RDWR);
 | |
| +
 | |
| +	if (!(option_mask32 & RNG_f)) { /* no -f */
 | |
| +		bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv);
 | |
| +		openlog(applet_name, LOG_PID, LOG_DAEMON);
 | |
| +		logmode = LOGMODE_SYSLOG;
 | |
| +	}
 | |
| +
 | |
| +	write_pidfile("/var/run/rngd.pid");
 | |
| +	for (;;) {
 | |
| +		xread(rng_fd, buf, sizeof buf);
 | |
| +
 | |
| +		fips = fips_run_rng_test(fipsctx, buf);
 | |
| +
 | |
| +		if (fips) {
 | |
| +			bb_info_msg("failed fips test");
 | |
| +			sleep(1);
 | |
| +			continue;
 | |
| +		}
 | |
| +
 | |
| +		for (p = buf; p + random_step <= &buf[sizeof buf]; p += random_step) {
 | |
| +			random_add_entropy(random_fd, p, random_step);
 | |
| +			random_sleep(random_fd, poll_timeout ? : -1.0, fill_watermark);
 | |
| +		}
 | |
| +	}
 | |
| +
 | |
| +	return EXIT_SUCCESS;
 | |
| +}
 | |
| +
 |