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;
|
|
+}
|
|
+
|