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; ilast32) 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 + +#ifndef __u32 +typedef unsigned int __u32; +#endif +#include /* 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; +} +