summaryrefslogtreecommitdiffstats
path: root/sys/dev/random
diff options
context:
space:
mode:
authormarkm <markm@FreeBSD.org>2014-10-30 21:21:53 +0000
committermarkm <markm@FreeBSD.org>2014-10-30 21:21:53 +0000
commitfce6747f55fd538917f2bd60e601dc95866c16d0 (patch)
treed5dfa61a018a7d209b25f173c6ee76709037035a /sys/dev/random
parentda82006ada584e84400ef56335e9df6c4e72bc6e (diff)
downloadFreeBSD-src-fce6747f55fd538917f2bd60e601dc95866c16d0.zip
FreeBSD-src-fce6747f55fd538917f2bd60e601dc95866c16d0.tar.gz
This is the much-discussed major upgrade to the random(4) device, known to you all as /dev/random.
This code has had an extensive rewrite and a good series of reviews, both by the author and other parties. This means a lot of code has been simplified. Pluggable structures for high-rate entropy generators are available, and it is most definitely not the case that /dev/random can be driven by only a hardware souce any more. This has been designed out of the device. Hardware sources are stirred into the CSPRNG (Yarrow, Fortuna) like any other entropy source. Pluggable modules may be written by third parties for additional sources. The harvesting structures and consequently the locking have been simplified. Entropy harvesting is done in a more general way (the documentation for this will follow). There is some GREAT entropy to be had in the UMA allocator, but it is disabled for now as messing with that is likely to annoy many people. The venerable (but effective) Yarrow algorithm, which is no longer supported by its authors now has an alternative, Fortuna. For now, Yarrow is retained as the default algorithm, but this may be changed using a kernel option. It is intended to make Fortuna the default algorithm for 11.0. Interested parties are encouraged to read ISBN 978-0-470-47424-2 "Cryptography Engineering" By Ferguson, Schneier and Kohno for Fortuna's gory details. Heck, read it anyway. Many thanks to Arthur Mesh who did early grunt work, and who got caught in the crossfire rather more than he deserved to. My thanks also to folks who helped me thresh this out on whiteboards and in the odd "Hallway track", or otherwise. My Nomex pants are on. Let the feedback commence! Reviewed by: trasz,des(partial),imp(partial?),rwatson(partial?) Approved by: so(des)
Diffstat (limited to 'sys/dev/random')
-rwxr-xr-xsys/dev/random/build.sh24
-rw-r--r--sys/dev/random/dummy_rng.c121
-rw-r--r--sys/dev/random/fortuna.c433
-rw-r--r--sys/dev/random/fortuna.h (renamed from sys/dev/random/rwfile.h)19
-rw-r--r--sys/dev/random/harvest.c141
-rw-r--r--sys/dev/random/hash.c21
-rw-r--r--sys/dev/random/hash.h2
-rw-r--r--sys/dev/random/ivy.c43
-rw-r--r--sys/dev/random/live_entropy_sources.c145
-rw-r--r--sys/dev/random/live_entropy_sources.h31
-rw-r--r--sys/dev/random/nehemiah.c37
-rw-r--r--sys/dev/random/random_adaptors.c486
-rw-r--r--sys/dev/random/random_adaptors.h61
-rw-r--r--sys/dev/random/random_harvestq.c428
-rw-r--r--sys/dev/random/random_harvestq.h40
-rw-r--r--sys/dev/random/randomdev.c271
-rw-r--r--sys/dev/random/randomdev.h51
-rw-r--r--sys/dev/random/randomdev_soft.c250
-rw-r--r--sys/dev/random/randomdev_soft.h51
-rw-r--r--sys/dev/random/rwfile.c96
-rw-r--r--sys/dev/random/uint128.h75
-rw-r--r--sys/dev/random/unit_test.c257
-rw-r--r--sys/dev/random/unit_test.h72
-rw-r--r--sys/dev/random/yarrow.c523
-rw-r--r--sys/dev/random/yarrow.h11
25 files changed, 2308 insertions, 1381 deletions
diff --git a/sys/dev/random/build.sh b/sys/dev/random/build.sh
new file mode 100755
index 0000000..e573dc1
--- /dev/null
+++ b/sys/dev/random/build.sh
@@ -0,0 +1,24 @@
+# $FreeBSD$
+#
+# Basic script to build crude unit tests.
+#
+cc -g -O0 -pthread -DRANDOM_DEBUG -DRANDOM_YARROW \
+ -I../.. -lstdthreads -Wall \
+ unit_test.c \
+ yarrow.c \
+ hash.c \
+ ../../crypto/rijndael/rijndael-api-fst.c \
+ ../../crypto/rijndael/rijndael-alg-fst.c \
+ ../../crypto/sha2/sha2.c \
+ ../../crypto/sha2/sha256c.c \
+ -o yunit_test
+cc -g -O0 -pthread -DRANDOM_DEBUG -DRANDOM_FORTUNA \
+ -I../.. -lstdthreads -Wall \
+ unit_test.c \
+ fortuna.c \
+ hash.c \
+ ../../crypto/rijndael/rijndael-api-fst.c \
+ ../../crypto/rijndael/rijndael-alg-fst.c \
+ ../../crypto/sha2/sha2.c \
+ ../../crypto/sha2/sha256c.c \
+ -o funit_test
diff --git a/sys/dev/random/dummy_rng.c b/sys/dev/random/dummy_rng.c
index 810a784..a7ca4b3 100644
--- a/sys/dev/random/dummy_rng.c
+++ b/sys/dev/random/dummy_rng.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
+ * Copyright (c) 2013 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,98 +28,92 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_random.h"
+
#include <sys/param.h>
+#include <sys/conf.h>
#include <sys/fcntl.h>
#include <sys/kernel.h>
+#include <sys/lock.h>
#include <sys/malloc.h>
-#include <sys/module.h>
#include <sys/random.h>
-#include <sys/selinfo.h>
+#include <sys/syslog.h>
#include <sys/systm.h>
-#include <sys/time.h>
-#include <dev/random/random_adaptors.h>
#include <dev/random/randomdev.h>
-
-static struct mtx dummy_random_mtx;
-
-/* Used to fake out unused random calls in random_adaptor */
-static void
-random_null_func(void)
-{
-}
+#include <dev/random/random_adaptors.h>
static int
-dummy_random_poll(int events __unused, struct thread *td __unused)
+dummy_random_zero(void)
{
return (0);
}
-static int
-dummy_random_block(int flag)
+static void
+dummy_random(void)
{
- int error = 0;
-
- mtx_lock(&dummy_random_mtx);
-
- /* Blocking logic */
- while (!error) {
- if (flag & O_NONBLOCK)
- error = EWOULDBLOCK;
- else {
- printf("random: dummy device blocking on read.\n");
- error = msleep(&dummy_random_block,
- &dummy_random_mtx,
- PUSER | PCATCH, "block", 0);
- }
- }
- mtx_unlock(&dummy_random_mtx);
-
- return (error);
}
+/* ARGSUSED */
static void
dummy_random_init(void)
{
- mtx_init(&dummy_random_mtx, "sleep mtx for dummy_random",
- NULL, MTX_DEF);
-}
-
-static void
-dummy_random_deinit(void)
-{
+#ifdef RANDOM_DEBUG
+ printf("random: %s\n", __func__);
+#endif
- mtx_destroy(&dummy_random_mtx);
+ randomdev_init_reader(dummy_random_read_phony);
}
-struct random_adaptor dummy_random = {
- .ident = "Dummy entropy device that always blocks",
- .init = dummy_random_init,
- .deinit = dummy_random_deinit,
- .block = dummy_random_block,
- .poll = dummy_random_poll,
- .read = (random_read_func_t *)random_null_func,
- .reseed = (random_reseed_func_t *)random_null_func,
- .seeded = 0, /* This device can never be seeded */
- .priority = 1, /* Bottom priority, so goes to last position */
-};
-
-static int
-dummy_random_modevent(module_t mod __unused, int type, void *unused __unused)
+/* This is used only by the internal read_random(9) call, and then only
+ * if no entropy processor is loaded.
+ *
+ * Make a token effort to provide _some_ kind of output. No warranty of
+ * the quality of this output is made, mainly because its lousy.
+ *
+ * This is only used by the internal read_random(9) call when no other
+ * adaptor is active.
+ *
+ * It has external scope due to the way things work in
+ * randomdev_[de]init_reader() that the rest of the world doesn't need to
+ * know about.
+ *
+ * Caveat Emptor.
+ */
+u_int
+dummy_random_read_phony(uint8_t *buf, u_int count)
{
+ /* If no entropy device is loaded, don't spam the console with warnings */
+ static int warned = 0;
+ u_long randval;
+ size_t size, i;
+
+ if (!warned) {
+ log(LOG_WARNING, "random device not loaded/active; using insecure pseudo-random number generator\n");
+ warned = 1;
+ }
- switch (type) {
- case MOD_LOAD:
- random_adaptor_register("dummy", &dummy_random);
- EVENTHANDLER_INVOKE(random_adaptor_attach,
- &dummy_random);
+ /* srandom() is called in kern/init_main.c:proc0_post() */
- return (0);
+ /* Fill buf[] with random(9) output */
+ for (i = 0; i < count; i += sizeof(randval)) {
+ randval = random();
+ size = MIN(count - i, sizeof(randval));
+ memcpy(buf + i, &randval, (size_t)size);
}
- return (EINVAL);
+ return (count);
}
-RANDOM_ADAPTOR_MODULE(dummy, dummy_random_modevent, 1);
+struct random_adaptor randomdev_dummy = {
+ .ra_ident = "Dummy",
+ .ra_priority = 1, /* Bottom priority, so goes to last position */
+ .ra_reseed = dummy_random,
+ .ra_seeded = (random_adaptor_seeded_func_t *)dummy_random_zero,
+ .ra_read = (random_adaptor_read_func_t *)dummy_random_zero,
+ .ra_write = (random_adaptor_write_func_t *)dummy_random_zero,
+ .ra_init = dummy_random_init,
+ .ra_deinit = dummy_random,
+};
diff --git a/sys/dev/random/fortuna.c b/sys/dev/random/fortuna.c
new file mode 100644
index 0000000..46ec88d
--- /dev/null
+++ b/sys/dev/random/fortuna.c
@@ -0,0 +1,433 @@
+/*-
+ * Copyright (c) 2013-2014 Mark R V Murray
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef _KERNEL
+#include "opt_random.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/random.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+
+#include <machine/cpu.h>
+
+#include <crypto/rijndael/rijndael-api-fst.h>
+#include <crypto/sha2/sha2.h>
+
+#include <dev/random/hash.h>
+#include <dev/random/randomdev.h>
+#include <dev/random/random_adaptors.h>
+#include <dev/random/random_harvestq.h>
+#include <dev/random/uint128.h>
+#include <dev/random/fortuna.h>
+#else /* !_KERNEL */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <threads.h>
+
+#include "unit_test.h"
+
+#include <crypto/rijndael/rijndael-api-fst.h>
+#include <crypto/sha2/sha2.h>
+
+#include <dev/random/hash.h>
+#include <dev/random/uint128.h>
+#include <dev/random/fortuna.h>
+#endif /* _KERNEL */
+
+#if !defined(RANDOM_YARROW) && !defined(RANDOM_FORTUNA)
+#define RANDOM_YARROW
+#elif defined(RANDOM_YARROW) && defined(RANDOM_FORTUNA)
+#error "Must define either RANDOM_YARROW or RANDOM_FORTUNA"
+#endif
+
+#if defined(RANDOM_FORTUNA)
+
+#define NPOOLS 32
+#define MINPOOLSIZE 64
+#define DEFPOOLSIZE 256
+#define MAXPOOLSIZE 65536
+
+/* This algorithm (and code) presumes that KEYSIZE is twice as large as BLOCKSIZE */
+CTASSERT(BLOCKSIZE == sizeof(uint128_t));
+CTASSERT(KEYSIZE == 2*BLOCKSIZE);
+
+/* This is the beastie that needs protecting. It contains all of the
+ * state that we are excited about.
+ * Exactly one is instantiated.
+ */
+static struct fortuna_state {
+ /* P_i */
+ struct pool {
+ u_int length;
+ struct randomdev_hash hash;
+ } pool[NPOOLS];
+
+ /* ReseedCnt */
+ u_int reseedcount;
+
+ /* C - 128 bits */
+ union {
+ uint8_t byte[BLOCKSIZE];
+ uint128_t whole;
+ } counter;
+
+ /* K */
+ struct randomdev_key key;
+
+ /* Extras */
+ u_int minpoolsize;
+
+ /* Extras for the OS */
+
+#ifdef _KERNEL
+ /* For use when 'pacing' the reseeds */
+ sbintime_t lasttime;
+#endif
+} fortuna_state;
+
+/* The random_reseed_mtx mutex protects seeding and polling/blocking. */
+static mtx_t random_reseed_mtx;
+
+static struct fortuna_start_cache {
+ uint8_t junk[PAGE_SIZE];
+ size_t length;
+ struct randomdev_hash hash;
+} fortuna_start_cache;
+
+#ifdef _KERNEL
+static struct sysctl_ctx_list random_clist;
+RANDOM_CHECK_UINT(minpoolsize, MINPOOLSIZE, MAXPOOLSIZE);
+#endif
+
+void
+random_fortuna_init_alg(void)
+{
+ int i;
+#ifdef _KERNEL
+ struct sysctl_oid *random_fortuna_o;
+#endif
+
+ memset(fortuna_start_cache.junk, 0, sizeof(fortuna_start_cache.junk));
+ fortuna_start_cache.length = 0U;
+ randomdev_hash_init(&fortuna_start_cache.hash);
+
+ /* Set up a lock for the reseed process */
+#ifdef _KERNEL
+ mtx_init(&random_reseed_mtx, "reseed mutex", NULL, MTX_DEF);
+#else /* !_KERNEL */
+ mtx_init(&random_reseed_mtx, mtx_plain);
+#endif /* _KERNEL */
+
+#ifdef _KERNEL
+ /* Fortuna parameters. Do not adjust these unless you have
+ * have a very good clue about what they do!
+ */
+ random_fortuna_o = SYSCTL_ADD_NODE(&random_clist,
+ SYSCTL_STATIC_CHILDREN(_kern_random),
+ OID_AUTO, "fortuna", CTLFLAG_RW, 0,
+ "Fortuna Parameters");
+
+ SYSCTL_ADD_PROC(&random_clist,
+ SYSCTL_CHILDREN(random_fortuna_o), OID_AUTO,
+ "minpoolsize", CTLTYPE_UINT|CTLFLAG_RW,
+ &fortuna_state.minpoolsize, DEFPOOLSIZE,
+ random_check_uint_minpoolsize, "IU",
+ "Minimum pool size necessary to cause a reseed automatically");
+
+ fortuna_state.lasttime = 0U;
+#endif
+
+ fortuna_state.minpoolsize = DEFPOOLSIZE;
+
+ /* F&S - InitializePRNG() */
+
+ /* F&S - P_i = \epsilon */
+ for (i = 0; i < NPOOLS; i++) {
+ randomdev_hash_init(&fortuna_state.pool[i].hash);
+ fortuna_state.pool[i].length = 0U;
+ }
+
+ /* F&S - ReseedCNT = 0 */
+ fortuna_state.reseedcount = 0U;
+
+ /* F&S - InitializeGenerator() */
+
+ /* F&S - C = 0 */
+ uint128_clear(&fortuna_state.counter.whole);
+
+ /* F&S - K = 0 */
+ memset(&fortuna_state.key, 0, sizeof(fortuna_state.key));
+}
+
+void
+random_fortuna_deinit_alg(void)
+{
+
+ mtx_destroy(&random_reseed_mtx);
+ memset(&fortuna_state, 0, sizeof(fortuna_state));
+}
+
+/* F&S - AddRandomEvent() */
+/* Process a single stochastic event off the harvest queue */
+void
+random_fortuna_process_event(struct harvest_event *event)
+{
+ u_int pl;
+
+ /* We must be locked for all this as plenty of state gets messed with */
+ mtx_lock(&random_reseed_mtx);
+
+ /* Accumulate the event into the appropriate pool
+ * where each event carries the destination information
+ */
+ /* F&S - P_i = P_i|<harvested stuff> */
+ /* The hash_init and hash_finish are done in random_fortuna_read() below */
+ pl = event->he_destination % NPOOLS;
+ randomdev_hash_iterate(&fortuna_state.pool[pl].hash, event, sizeof(*event));
+ /* No point in counting above the outside maximum */
+ fortuna_state.pool[pl].length += event->he_size;
+ fortuna_state.pool[pl].length = MIN(fortuna_state.pool[pl].length, MAXPOOLSIZE);
+
+ /* Done with state-messing */
+ mtx_unlock(&random_reseed_mtx);
+}
+
+/* F&S - Reseed() */
+/* Reseed Mutex is held */
+static void
+reseed(uint8_t *junk, u_int length)
+{
+ struct randomdev_hash context;
+ uint8_t hash[KEYSIZE], temp[KEYSIZE];
+
+ KASSERT(fortuna_state.minpoolsize > 0, ("random: Fortuna threshold = 0"));
+#ifdef _KERNEL
+ mtx_assert(&random_reseed_mtx, MA_OWNED);
+#endif
+
+ /* F&S - temp = H(K|s) */
+ randomdev_hash_init(&context);
+ randomdev_hash_iterate(&context, &fortuna_state.key, sizeof(fortuna_state.key));
+ randomdev_hash_iterate(&context, junk, length);
+ randomdev_hash_finish(&context, temp);
+
+ /* F&S - hash = H(temp) */
+ randomdev_hash_init(&context);
+ randomdev_hash_iterate(&context, temp, KEYSIZE);
+ randomdev_hash_finish(&context, hash);
+
+ /* F&S - K = hash */
+ randomdev_encrypt_init(&fortuna_state.key, temp);
+ memset(temp, 0, sizeof(temp));
+ memset(hash, 0, sizeof(hash));
+
+ /* Unblock the device if it was blocked due to being unseeded */
+ if (uint128_is_zero(fortuna_state.counter.whole))
+ random_adaptor_unblock();
+ /* F&S - C = C + 1 */
+ uint128_increment(&fortuna_state.counter.whole);
+}
+
+/* F&S - GenerateBlocks() */
+/* Reseed Mutex is held, and buf points to a whole number of blocks. */
+static __inline void
+random_fortuna_genblocks(uint8_t *buf, u_int blockcount)
+{
+ u_int i;
+
+ for (i = 0u; i < blockcount; i++) {
+ /* F&S - r = r|E(K,C) */
+ randomdev_encrypt(&fortuna_state.key, fortuna_state.counter.byte, buf, BLOCKSIZE);
+ buf += BLOCKSIZE;
+
+ /* F&S - C = C + 1 */
+ uint128_increment(&fortuna_state.counter.whole);
+ }
+}
+
+/* F&S - PseudoRandomData() */
+/* Reseed Mutex is held, and buf points to a whole number of blocks. */
+static __inline void
+random_fortuna_genrandom(uint8_t *buf, u_int bytecount)
+{
+ static uint8_t temp[BLOCKSIZE*(KEYSIZE/BLOCKSIZE)];
+ u_int blockcount;
+
+ /* F&S - assert(n < 2^20) */
+ KASSERT((bytecount <= (1 << 20)), ("invalid single read request to fortuna of %d bytes", bytecount));
+
+ /* F&S - r = first-n-bytes(GenerateBlocks(ceil(n/16))) */
+ blockcount = (bytecount + BLOCKSIZE - 1)/BLOCKSIZE;
+ random_fortuna_genblocks(buf, blockcount);
+
+ /* F&S - K = GenerateBlocks(2) */
+ random_fortuna_genblocks(temp, KEYSIZE/BLOCKSIZE);
+ randomdev_encrypt_init(&fortuna_state.key, temp);
+ memset(temp, 0, sizeof(temp));
+}
+
+/* F&S - RandomData() */
+/* Used to return processed entropy from the PRNG */
+/* The argument buf points to a whole number of blocks. */
+void
+random_fortuna_read(uint8_t *buf, u_int bytecount)
+{
+#ifdef _KERNEL
+ sbintime_t thistime;
+#endif
+ struct randomdev_hash context;
+ uint8_t s[NPOOLS*KEYSIZE], temp[KEYSIZE];
+ int i;
+ u_int seedlength;
+
+ /* We must be locked for all this as plenty of state gets messed with */
+ mtx_lock(&random_reseed_mtx);
+
+ /* if buf == NULL and bytecount == 0 then this is the pre-read. */
+ /* if buf == NULL and bytecount != 0 then this is the post-read; ignore. */
+ if (buf == NULL) {
+ if (bytecount == 0) {
+ if (fortuna_state.pool[0].length >= fortuna_state.minpoolsize
+#ifdef _KERNEL
+ /* F&S - Use 'getsbinuptime()' to prevent reseed-spamming. */
+ && ((thistime = getsbinuptime()) - fortuna_state.lasttime > hz/10)
+#endif
+ ) {
+#ifdef _KERNEL
+ fortuna_state.lasttime = thistime;
+#endif
+
+ seedlength = 0U;
+ /* F&S - ReseedCNT = ReseedCNT + 1 */
+ fortuna_state.reseedcount++;
+ /* s = \epsilon by default */
+ for (i = 0; i < NPOOLS; i++) {
+ /* F&S - if Divides(ReseedCnt, 2^i) ... */
+ if ((fortuna_state.reseedcount % (1 << i)) == 0U) {
+ seedlength += KEYSIZE;
+ /* F&S - temp = (P_i) */
+ randomdev_hash_finish(&fortuna_state.pool[i].hash, temp);
+ /* F&S - P_i = \epsilon */
+ randomdev_hash_init(&fortuna_state.pool[i].hash);
+ fortuna_state.pool[i].length = 0U;
+ /* F&S - s = s|H(temp) */
+ randomdev_hash_init(&context);
+ randomdev_hash_iterate(&context, temp, KEYSIZE);
+ randomdev_hash_finish(&context, s + i*KEYSIZE);
+ }
+ else
+ break;
+ }
+#ifdef RANDOM_DEBUG
+ printf("random: active reseed: reseedcount [%d] ", fortuna_state.reseedcount);
+ for (i = 0; i < NPOOLS; i++)
+ printf(" %d", fortuna_state.pool[i].length);
+ printf("\n");
+#endif
+ /* F&S */
+ reseed(s, seedlength);
+
+ /* Clean up */
+ memset(s, 0, seedlength);
+ seedlength = 0U;
+ memset(temp, 0, sizeof(temp));
+ memset(&context, 0, sizeof(context));
+ }
+ }
+ }
+ /* if buf != NULL do a regular read. */
+ else
+ random_fortuna_genrandom(buf, bytecount);
+
+ mtx_unlock(&random_reseed_mtx);
+}
+
+/* Internal function to hand external entropy to the PRNG */
+void
+random_fortuna_write(uint8_t *buf, u_int count)
+{
+ uint8_t temp[KEYSIZE];
+ int i;
+ uintmax_t timestamp;
+
+ timestamp = get_cyclecount();
+ randomdev_hash_iterate(&fortuna_start_cache.hash, &timestamp, sizeof(timestamp));
+ randomdev_hash_iterate(&fortuna_start_cache.hash, buf, count);
+ timestamp = get_cyclecount();
+ randomdev_hash_iterate(&fortuna_start_cache.hash, &timestamp, sizeof(timestamp));
+ randomdev_hash_finish(&fortuna_start_cache.hash, temp);
+ for (i = 0; i < KEYSIZE; i++)
+ fortuna_start_cache.junk[(fortuna_start_cache.length + i)%PAGE_SIZE] ^= temp[i];
+ fortuna_start_cache.length += KEYSIZE;
+
+#ifdef RANDOM_DEBUG
+ printf("random: %s - ", __func__);
+ for (i = 0; i < KEYSIZE; i++)
+ printf("%02X", temp[i]);
+ printf("\n");
+#endif
+
+ memset(temp, 0, KEYSIZE);
+
+ /* We must be locked for all this as plenty of state gets messed with */
+ mtx_lock(&random_reseed_mtx);
+
+ randomdev_hash_init(&fortuna_start_cache.hash);
+
+ reseed(fortuna_start_cache.junk, MIN(PAGE_SIZE, fortuna_start_cache.length));
+ memset(fortuna_start_cache.junk, 0, sizeof(fortuna_start_cache.junk));
+
+ mtx_unlock(&random_reseed_mtx);
+}
+
+void
+random_fortuna_reseed(void)
+{
+
+ /* CWOT */
+}
+
+int
+random_fortuna_seeded(void)
+{
+
+ return (!uint128_is_zero(fortuna_state.counter.whole));
+}
+
+#endif /* RANDOM_FORTUNA */
diff --git a/sys/dev/random/rwfile.h b/sys/dev/random/fortuna.h
index f14fd7b..81fcac3 100644
--- a/sys/dev/random/rwfile.h
+++ b/sys/dev/random/fortuna.h
@@ -26,14 +26,19 @@
* $FreeBSD$
*/
-#ifndef SYS_DEV_RANDOM_RWFILE_H_INCLUDED
-#define SYS_DEV_RANDOM_RWFILE_H_INCLUDED
-
-#ifdef RANDOM_RWFILE
-
-int randomdev_read_file(const char *filename, void *buf, size_t);
-int randomdev_write_file(const char *filename, void *buf, size_t);
+#ifndef SYS_DEV_RANDOM_FORTUNA_H_INCLUDED
+#define SYS_DEV_RANDOM_FORTUNA_H_INCLUDED
+#ifdef _KERNEL
+typedef struct mtx mtx_t;
#endif
+void random_fortuna_init_alg(void);
+void random_fortuna_deinit_alg(void);
+void random_fortuna_read(uint8_t *, u_int);
+void random_fortuna_write(uint8_t *, u_int);
+void random_fortuna_reseed(void);
+int random_fortuna_seeded(void);
+void random_fortuna_process_event(struct harvest_event *event);
+
#endif
diff --git a/sys/dev/random/harvest.c b/sys/dev/random/harvest.c
deleted file mode 100644
index 9dbae84..0000000
--- a/sys/dev/random/harvest.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*-
- * Copyright (c) 2000-2013 Mark R V Murray
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer
- * in this position and unchanged.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/kthread.h>
-#include <sys/lock.h>
-#include <sys/malloc.h>
-#include <sys/mutex.h>
-#include <sys/poll.h>
-#include <sys/queue.h>
-#include <sys/random.h>
-#include <sys/selinfo.h>
-#include <sys/syslog.h>
-#include <sys/systm.h>
-#include <sys/sysctl.h>
-
-#include <machine/cpu.h>
-
-#include <dev/random/randomdev_soft.h>
-
-static int read_random_phony(void *, int);
-
-/* Structure holding the desired entropy sources */
-struct harvest_select harvest = { 1, 1, 1, 1 };
-static int warned = 0;
-
-/* hold the address of the routine which is actually called if
- * the randomdev is loaded
- */
-static void (*reap_func)(u_int64_t, const void *, u_int, u_int,
- enum esource) = NULL;
-static int (*read_func)(void *, int) = read_random_phony;
-
-/* Initialise the harvester at load time */
-void
-randomdev_init_harvester(void (*reaper)(u_int64_t, const void *, u_int,
- u_int, enum esource), int (*reader)(void *, int))
-{
- reap_func = reaper;
- read_func = reader;
-}
-
-/* Deinitialise the harvester at unload time */
-void
-randomdev_deinit_harvester(void)
-{
- reap_func = NULL;
- read_func = read_random_phony;
- warned = 0;
-}
-
-/* Entropy harvesting routine. This is supposed to be fast; do
- * not do anything slow in here!
- * Implemented as in indirect call to allow non-inclusion of
- * the entropy device.
- *
- * XXXRW: get_cyclecount() is cheap on most modern hardware, where cycle
- * counters are built in, but on older hardware it will do a real time clock
- * read which can be quite expensive.
- */
-void
-random_harvest(const void *entropy, u_int count, u_int bits, enum esource origin)
-{
- if (reap_func)
- (*reap_func)(get_cyclecount(), entropy, count, bits, origin);
-}
-
-/* Userland-visible version of read_random */
-int
-read_random(void *buf, int count)
-{
- return ((*read_func)(buf, count));
-}
-
-/* If the entropy device is not loaded, make a token effort to
- * provide _some_ kind of randomness. This should only be used
- * inside other RNG's, like arc4random(9).
- */
-static int
-read_random_phony(void *buf, int count)
-{
- u_long randval;
- int size, i;
-
- if (!warned) {
- log(LOG_WARNING, "random device not loaded; using insecure entropy\n");
- warned = 1;
- }
-
- /* srandom() is called in kern/init_main.c:proc0_post() */
-
- /* Fill buf[] with random(9) output */
- for (i = 0; i < count; i+= (int)sizeof(u_long)) {
- randval = random();
- size = MIN(count - i, sizeof(u_long));
- memcpy(&((char *)buf)[i], &randval, (size_t)size);
- }
-
- return (count);
-}
-
-/* Helper routine to enable kproc_exit() to work while the module is
- * being (or has been) unloaded.
- * This routine is in this file because it is always linked into the kernel,
- * and will thus never be unloaded. This is critical for unloadable modules
- * that have threads.
- */
-void
-random_set_wakeup_exit(void *control)
-{
- wakeup(control);
- kproc_exit(0);
- /* NOTREACHED */
-}
diff --git a/sys/dev/random/hash.c b/sys/dev/random/hash.c
index cf0feaa..7deee87 100644
--- a/sys/dev/random/hash.c
+++ b/sys/dev/random/hash.c
@@ -28,18 +28,33 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#ifdef _KERNEL
#include <sys/param.h>
#include <sys/systm.h>
+#else /* !_KERNEL */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <threads.h>
+#include "unit_test.h"
+#endif /* _KERNEL */
#include <crypto/rijndael/rijndael-api-fst.h>
#include <crypto/sha2/sha2.h>
#include <dev/random/hash.h>
+/* This code presumes that KEYSIZE is twice as large as BLOCKSIZE */
+CTASSERT(KEYSIZE == 2*BLOCKSIZE);
+
/* Initialise the hash */
void
randomdev_hash_init(struct randomdev_hash *context)
{
+
SHA256_Init(&context->sha);
}
@@ -47,6 +62,7 @@ randomdev_hash_init(struct randomdev_hash *context)
void
randomdev_hash_iterate(struct randomdev_hash *context, void *data, size_t size)
{
+
SHA256_Update(&context->sha, data, size);
}
@@ -56,6 +72,7 @@ randomdev_hash_iterate(struct randomdev_hash *context, void *data, size_t size)
void
randomdev_hash_finish(struct randomdev_hash *context, void *buf)
{
+
SHA256_Final(buf, &context->sha);
}
@@ -66,6 +83,7 @@ randomdev_hash_finish(struct randomdev_hash *context, void *buf)
void
randomdev_encrypt_init(struct randomdev_key *context, void *data)
{
+
rijndael_cipherInit(&context->cipher, MODE_CBC, NULL);
rijndael_makeKey(&context->key, DIR_ENCRYPT, KEYSIZE*8, data);
}
@@ -75,7 +93,8 @@ randomdev_encrypt_init(struct randomdev_key *context, void *data)
* a multiple of BLOCKSIZE.
*/
void
-randomdev_encrypt(struct randomdev_key *context, void *d_in, void *d_out, unsigned length)
+randomdev_encrypt(struct randomdev_key *context, void *d_in, void *d_out, u_int length)
{
+
rijndael_blockEncrypt(&context->cipher, &context->key, d_in, length*8, d_out);
}
diff --git a/sys/dev/random/hash.h b/sys/dev/random/hash.h
index 4e6a4a0..57c0c6d 100644
--- a/sys/dev/random/hash.h
+++ b/sys/dev/random/hash.h
@@ -45,6 +45,6 @@ void randomdev_hash_init(struct randomdev_hash *);
void randomdev_hash_iterate(struct randomdev_hash *, void *, size_t);
void randomdev_hash_finish(struct randomdev_hash *, void *);
void randomdev_encrypt_init(struct randomdev_key *, void *);
-void randomdev_encrypt(struct randomdev_key *context, void *, void *, unsigned);
+void randomdev_encrypt(struct randomdev_key *context, void *, void *, u_int);
#endif
diff --git a/sys/dev/random/ivy.c b/sys/dev/random/ivy.c
index 23fd542..724e7aa 100644
--- a/sys/dev/random/ivy.c
+++ b/sys/dev/random/ivy.c
@@ -35,11 +35,11 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
+#include <sys/conf.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/random.h>
-#include <sys/selinfo.h>
#include <sys/systm.h>
#include <machine/md_var.h>
@@ -47,18 +47,17 @@ __FBSDID("$FreeBSD$");
#include <dev/random/randomdev.h>
#include <dev/random/randomdev_soft.h>
-#include <dev/random/random_harvestq.h>
-#include <dev/random/live_entropy_sources.h>
#include <dev/random/random_adaptors.h>
+#include <dev/random/live_entropy_sources.h>
#define RETRY_COUNT 10
-static int random_ivy_read(void *, int);
+static u_int random_ivy_read(void *, u_int);
-static struct random_hardware_source random_ivy = {
- .ident = "Hardware, Intel Secure Key RNG",
- .source = RANDOM_PURE_RDRAND,
- .read = random_ivy_read
+static struct live_entropy_source random_ivy = {
+ .les_ident = "Intel Secure Key RNG",
+ .les_source = RANDOM_PURE_RDRAND,
+ .les_read = random_ivy_read
};
static inline int
@@ -86,15 +85,17 @@ ivy_rng_store(long *buf)
#endif
}
-static int
-random_ivy_read(void *buf, int c)
+/* It is specifically allowed that buf is a multiple of sizeof(long) */
+static u_int
+random_ivy_read(void *buf, u_int c)
{
long *b;
- int count;
+ u_int count;
- KASSERT(c % sizeof(long) == 0, ("partial read %d", c));
- for (b = buf, count = c; count > 0; count -= sizeof(long), b++) {
- if (ivy_rng_store(b) == 0)
+ KASSERT(c % sizeof(*b) == 0, ("partial read %d", c));
+ b = buf;
+ for (count = c; count > 0; count -= sizeof(*b)) {
+ if (ivy_rng_store(b++) == 0)
break;
}
return (c - count);
@@ -107,14 +108,10 @@ rdrand_modevent(module_t mod, int type, void *unused)
switch (type) {
case MOD_LOAD:
- if (cpu_feature2 & CPUID2_RDRAND)
+ if (cpu_feature2 & CPUID2_RDRAND) {
live_entropy_source_register(&random_ivy);
- else
-#ifndef KLD_MODULE
- if (bootverbose)
-#endif
- printf("%s: RDRAND is not present\n",
- random_ivy.ident);
+ printf("random: live provider: \"%s\"\n", random_ivy.les_ident);
+ }
break;
case MOD_UNLOAD:
@@ -134,4 +131,6 @@ rdrand_modevent(module_t mod, int type, void *unused)
return (error);
}
-LIVE_ENTROPY_SRC_MODULE(random_rdrand, rdrand_modevent, 1);
+DEV_MODULE(rdrand, rdrand_modevent, NULL);
+MODULE_VERSION(rdrand, 1);
+MODULE_DEPEND(rdrand, random_adaptors, 1, 1, 1);
diff --git a/sys/dev/random/live_entropy_sources.c b/sys/dev/random/live_entropy_sources.c
index d406ebd..9899cb4 100644
--- a/sys/dev/random/live_entropy_sources.c
+++ b/sys/dev/random/live_entropy_sources.c
@@ -28,13 +28,16 @@
#include <sys/param.h>
__FBSDID("$FreeBSD$");
+#include "opt_random.h"
+
#include <sys/kernel.h>
#include <sys/libkern.h>
#include <sys/lock.h>
#include <sys/malloc.h>
+#include <sys/module.h>
#include <sys/queue.h>
#include <sys/random.h>
-#include <sys/selinfo.h>
+#include <sys/sbuf.h>
#include <sys/sx.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
@@ -49,89 +52,73 @@ __FBSDID("$FreeBSD$");
#include "live_entropy_sources.h"
-LIST_HEAD(les_head, live_entropy_sources);
-static struct les_head sources = LIST_HEAD_INITIALIZER(sources);
-
/*
- * The live_lock protects the consistency of the "struct les_head sources"
+ * The les_lock protects the consistency of the "struct les_head les_sources"
*/
-static struct sx les_lock; /* need a sleepable lock */
+static struct sx les_lock; /* Need a sleepable lock for the sbuf/sysctl stuff. */
+
+LIST_HEAD(les_head, live_entropy_sources);
+static struct les_head les_sources = LIST_HEAD_INITIALIZER(les_sources);
void
-live_entropy_source_register(struct random_hardware_source *rsource)
+live_entropy_source_register(struct live_entropy_source *rsource)
{
- struct live_entropy_sources *les;
+ struct live_entropy_sources *lles;
KASSERT(rsource != NULL, ("invalid input to %s", __func__));
- les = malloc(sizeof(struct live_entropy_sources), M_ENTROPY, M_WAITOK);
- les->rsource = rsource;
+ lles = malloc(sizeof(*lles), M_ENTROPY, M_WAITOK);
+ lles->lles_rsource = rsource;
sx_xlock(&les_lock);
- LIST_INSERT_HEAD(&sources, les, entries);
+ LIST_INSERT_HEAD(&les_sources, lles, lles_entries);
sx_xunlock(&les_lock);
}
void
-live_entropy_source_deregister(struct random_hardware_source *rsource)
+live_entropy_source_deregister(struct live_entropy_source *rsource)
{
- struct live_entropy_sources *les = NULL;
+ struct live_entropy_sources *lles = NULL;
KASSERT(rsource != NULL, ("invalid input to %s", __func__));
sx_xlock(&les_lock);
- LIST_FOREACH(les, &sources, entries)
- if (les->rsource == rsource) {
- LIST_REMOVE(les, entries);
+ LIST_FOREACH(lles, &les_sources, lles_entries)
+ if (lles->lles_rsource == rsource) {
+ LIST_REMOVE(lles, lles_entries);
break;
}
sx_xunlock(&les_lock);
- if (les != NULL)
- free(les, M_ENTROPY);
+ if (lles != NULL)
+ free(lles, M_ENTROPY);
}
static int
live_entropy_source_handler(SYSCTL_HANDLER_ARGS)
{
- struct live_entropy_sources *les;
+ struct live_entropy_sources *lles;
+ struct sbuf sbuf;
int error, count;
- count = error = 0;
-
sx_slock(&les_lock);
- if (LIST_EMPTY(&sources))
- error = SYSCTL_OUT(req, "", 0);
- else {
- LIST_FOREACH(les, &sources, entries) {
-
- error = SYSCTL_OUT(req, ",", count++ ? 1 : 0);
- if (error)
- break;
+ sbuf_new_for_sysctl(&sbuf, NULL, 64, req);
- error = SYSCTL_OUT(req, les->rsource->ident, strlen(les->rsource->ident));
- if (error)
- break;
- }
+ count = 0;
+ LIST_FOREACH(lles, &les_sources, lles_entries) {
+ sbuf_cat(&sbuf, (count++ ? ",'" : "'"));
+ sbuf_cat(&sbuf, lles->lles_rsource->les_ident);
+ sbuf_cat(&sbuf, "'");
}
+ error = sbuf_finish(&sbuf);
+ sbuf_delete(&sbuf);
+
sx_sunlock(&les_lock);
return (error);
}
-static void
-live_entropy_sources_init(void *unused)
-{
-
- SYSCTL_PROC(_kern_random, OID_AUTO, live_entropy_sources,
- CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
- NULL, 0, live_entropy_source_handler, "",
- "List of Active Live Entropy Sources");
-
- sx_init(&les_lock, "live_entropy_sources");
-}
-
/*
* Run through all "live" sources reading entropy for the given
* number of rounds, which should be a multiple of the number
@@ -140,15 +127,18 @@ live_entropy_sources_init(void *unused)
*
* BEWARE!!!
* This function runs inside the RNG thread! Don't do anything silly!
- * Remember that we are NOT holding harvest_mtx on entry!
+ */
+/* XXXRW: get_cyclecount() is cheap on most modern hardware, where cycle
+ * counters are built in, but on older hardware it will do a real time clock
+ * read which can be quite expensive.
*/
void
-live_entropy_sources_feed(int rounds, event_proc_f entropy_processor)
+live_entropy_sources_feed(void)
{
- static struct harvest event;
- static uint8_t buf[HARVESTSIZE];
- struct live_entropy_sources *les;
- int i, n;
+ static struct harvest_event event;
+ struct live_entropy_sources *lles;
+ int i, read_rate;
+ u_int n;
sx_slock(&les_lock);
@@ -156,25 +146,23 @@ live_entropy_sources_feed(int rounds, event_proc_f entropy_processor)
* Walk over all of live entropy sources, and feed their output
* to the system-wide RNG.
*/
- LIST_FOREACH(les, &sources, entries) {
-
- for (i = 0; i < rounds; i++) {
- /*
- * This should be quick, since it's a live entropy
- * source.
- */
- /* FIXME: Whine loudly if this didn't work. */
- n = les->rsource->read(buf, sizeof(buf));
- n = MIN(n, HARVESTSIZE);
-
- event.somecounter = get_cyclecount();
- event.size = n;
- event.bits = (n*8)/2;
- event.source = les->rsource->source;
- memcpy(event.entropy, buf, n);
+ read_rate = random_adaptor_read_rate();
+ LIST_FOREACH(lles, &les_sources, lles_entries) {
+
+ for (i = 0; i < harvest_pool_count*read_rate; i++) {
+ /* This *must* be quick, since it's a live entropy source. */
+ n = lles->lles_rsource->les_read(event.he_entropy, HARVESTSIZE);
+ KASSERT((n > 0 && n <= HARVESTSIZE), ("very bad return from les_read (= %d) in %s", n, __func__));
+ memset(event.he_entropy + n, 0, HARVESTSIZE - n);
+
+ event.he_somecounter = get_cyclecount();
+ event.he_size = n;
+ event.he_bits = (n*8)/2;
+ event.he_source = lles->lles_rsource->les_source;
+ event.he_destination = harvest_destination[event.he_source]++;
/* Do the actual entropy insertion */
- entropy_processor(&event);
+ harvest_process_event(&event);
}
}
@@ -182,14 +170,21 @@ live_entropy_sources_feed(int rounds, event_proc_f entropy_processor)
sx_sunlock(&les_lock);
}
-static void
-live_entropy_sources_deinit(void *unused)
+void
+live_entropy_sources_init(void)
{
- sx_destroy(&les_lock);
+ SYSCTL_PROC(_kern_random, OID_AUTO, live_entropy_sources,
+ CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ NULL, 0, live_entropy_source_handler, "",
+ "List of Active Live Entropy Sources");
+
+ sx_init(&les_lock, "live_entropy_sources");
}
-SYSINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST,
- live_entropy_sources_init, NULL);
-SYSUNINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST,
- live_entropy_sources_deinit, NULL);
+void
+live_entropy_sources_deinit(void)
+{
+
+ sx_destroy(&les_lock);
+}
diff --git a/sys/dev/random/live_entropy_sources.h b/sys/dev/random/live_entropy_sources.h
index 9a23070..95e2e4b 100644
--- a/sys/dev/random/live_entropy_sources.h
+++ b/sys/dev/random/live_entropy_sources.h
@@ -30,31 +30,30 @@
#ifndef SYS_DEV_RANDOM_LIVE_ENTROPY_SOURCES_H_INCLUDED
#define SYS_DEV_RANDOM_LIVE_ENTROPY_SOURCES_H_INCLUDED
+typedef u_int random_live_read_func_t(void *, u_int);
+
/*
* Live entropy source is a source of entropy that can provide
* specified or approximate amount of entropy immediately upon request or within
* an acceptable amount of time.
*/
+struct live_entropy_source {
+ const char *les_ident;
+ enum random_entropy_source les_source;
+ random_live_read_func_t *les_read;
+};
+
struct live_entropy_sources {
- LIST_ENTRY(live_entropy_sources) entries; /* list of providers */
- struct random_hardware_source *rsource; /* associated random adaptor */
+ LIST_ENTRY(live_entropy_sources) lles_entries; /* list of providers */
+ struct live_entropy_source *lles_rsource; /* associated random adaptor */
};
extern struct mtx live_mtx;
-void live_entropy_source_register(struct random_hardware_source *);
-void live_entropy_source_deregister(struct random_hardware_source *);
-void live_entropy_sources_feed(int, event_proc_f);
-
-#define LIVE_ENTROPY_SRC_MODULE(name, modevent, ver) \
- static moduledata_t name##_mod = { \
- #name, \
- modevent, \
- 0 \
- }; \
- DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, \
- SI_ORDER_SECOND); \
- MODULE_VERSION(name, ver); \
- MODULE_DEPEND(name, random, 1, 1, 1);
+void live_entropy_sources_init(void);
+void live_entropy_sources_deinit(void);
+void live_entropy_source_register(struct live_entropy_source *);
+void live_entropy_source_deregister(struct live_entropy_source *);
+void live_entropy_sources_feed(void);
#endif /* SYS_DEV_RANDOM_LIVE_ENTROPY_SOURCES_H_INCLUDED */
diff --git a/sys/dev/random/nehemiah.c b/sys/dev/random/nehemiah.c
index b60689e..4740250 100644
--- a/sys/dev/random/nehemiah.c
+++ b/sys/dev/random/nehemiah.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2013 Mark R V Murray
+ * Copyright (c) 2013 David E. O'Brien <obrien@NUXI.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,11 +31,11 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
+#include <sys/conf.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/random.h>
-#include <sys/selinfo.h>
#include <sys/systm.h>
#include <machine/segments.h>
@@ -44,21 +45,20 @@ __FBSDID("$FreeBSD$");
#include <dev/random/randomdev.h>
#include <dev/random/randomdev_soft.h>
-#include <dev/random/random_harvestq.h>
-#include <dev/random/live_entropy_sources.h>
#include <dev/random/random_adaptors.h>
+#include <dev/random/live_entropy_sources.h>
static void random_nehemiah_init(void);
static void random_nehemiah_deinit(void);
-static int random_nehemiah_read(void *, int);
+static u_int random_nehemiah_read(void *, u_int);
-static struct random_hardware_source random_nehemiah = {
- .ident = "Hardware, VIA Nehemiah Padlock RNG",
- .source = RANDOM_PURE_NEHEMIAH,
- .read = random_nehemiah_read
+static struct live_entropy_source random_nehemiah = {
+ .les_ident = "VIA Nehemiah Padlock RNG",
+ .les_source = RANDOM_PURE_NEHEMIAH,
+ .les_read = random_nehemiah_read
};
-/* TODO: now that the Davies-Meyer hash is gone and we only use
+/* XXX: FIX? Now that the Davies-Meyer hash is gone and we only use
* the 'xstore' instruction, do we still need to preserve the
* FPU state with fpu_kern_(enter|leave)() ?
*/
@@ -75,7 +75,7 @@ VIA_RNG_store(void *buf)
#ifdef __GNUCLIKE_ASM
__asm __volatile(
"movl $0,%%edx\n\t"
- ".byte 0x0f, 0xa7, 0xc0" /* xstore */
+ "xstore"
: "=a" (retval), "+d" (rate), "+D" (buf)
:
: "memory"
@@ -100,8 +100,9 @@ random_nehemiah_deinit(void)
fpu_kern_free_ctx(fpu_ctx_save);
}
-static int
-random_nehemiah_read(void *buf, int c)
+/* It is specifically allowed that buf is a multiple of sizeof(long) */
+static u_int
+random_nehemiah_read(void *buf, u_int c)
{
uint8_t *b;
size_t count, ret;
@@ -131,13 +132,9 @@ nehemiah_modevent(module_t mod, int type, void *unused)
case MOD_LOAD:
if (via_feature_rng & VIA_HAS_RNG) {
live_entropy_source_register(&random_nehemiah);
+ printf("random: live provider: \"%s\"\n", random_nehemiah.les_ident);
random_nehemiah_init();
- } else
-#ifndef KLD_MODULE
- if (bootverbose)
-#endif
- printf("%s: VIA Padlock RNG not present\n",
- random_nehemiah.ident);
+ }
break;
case MOD_UNLOAD:
@@ -158,4 +155,6 @@ nehemiah_modevent(module_t mod, int type, void *unused)
return (error);
}
-LIVE_ENTROPY_SRC_MODULE(nehemiah, nehemiah_modevent, 1);
+DEV_MODULE(nehemiah, nehemiah_modevent, NULL);
+MODULE_VERSION(nehemiah, 1);
+MODULE_DEPEND(nehemiah, random_adaptors, 1, 1, 1);
diff --git a/sys/dev/random/random_adaptors.c b/sys/dev/random/random_adaptors.c
index aa6db7b..c58f929 100644
--- a/sys/dev/random/random_adaptors.c
+++ b/sys/dev/random/random_adaptors.c
@@ -1,7 +1,7 @@
/*-
+ * Copyright (c) 2013 Mark R V Murray
* Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
* Copyright (c) 2013 David E. O'Brien <obrien@NUXI.org>
- * Copyright (c) 2013 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,195 +29,383 @@
#include <sys/param.h>
__FBSDID("$FreeBSD$");
+#include "opt_random.h"
+
#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/fcntl.h>
#include <sys/kernel.h>
#include <sys/kthread.h>
#include <sys/libkern.h>
#include <sys/lock.h>
#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/poll.h>
#include <sys/queue.h>
#include <sys/random.h>
+#include <sys/sbuf.h>
#include <sys/selinfo.h>
#include <sys/sx.h>
#include <sys/sysctl.h>
+#include <sys/uio.h>
#include <sys/unistd.h>
#include <dev/random/randomdev.h>
-#include <dev/random/randomdev_soft.h>
#include <dev/random/random_adaptors.h>
+#include <dev/random/live_entropy_sources.h>
+/* The random_adaptors_lock protects random_adaptors_list and friends and random_adaptor.
+ * We need a sleepable lock for uiomove/block/poll/sbuf/sysctl.
+ */
+static struct sx random_adaptors_lock;
LIST_HEAD(adaptors_head, random_adaptors);
-static struct adaptors_head adaptors = LIST_HEAD_INITIALIZER(adaptors);
-static struct sx adaptors_lock; /* need a sleepable lock */
-
-/* List for the dynamic sysctls */
-static struct sysctl_ctx_list random_clist;
+static struct adaptors_head random_adaptors_list = LIST_HEAD_INITIALIZER(random_adaptors_list);
+static struct random_adaptor *random_adaptor = NULL; /* Currently active adaptor */
+/* End of data items requiring random_adaptors_lock protection */
-struct random_adaptor *random_adaptor;
+/* The random_readrate_mtx mutex protects the read-rate estimator.
+ */
+static struct mtx random_read_rate_mtx;
+static int random_adaptor_read_rate_cache;
+/* End of data items requiring random_readrate_mtx mutex protection */
-MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures");
+static struct selinfo rsel;
-int
-random_adaptor_register(const char *name, struct random_adaptor *rsp)
+/* Utility routine to change active adaptor when the random_adaptors_list
+ * gets modified.
+ *
+ * Walk a list of registered random(4) adaptors and pick either a requested
+ * one or the highest priority one, whichever comes first. Panic on failure
+ * as the fallback must always be the "dummy" adaptor.
+ */
+static void
+random_adaptor_choose(void)
{
- struct random_adaptors *rpp;
+ char rngs[128], *token, *cp;
+ struct random_adaptors *rra, *rrai;
+ struct random_adaptor *random_adaptor_previous;
+ int primax;
- KASSERT(name != NULL && rsp != NULL, ("invalid input to %s", __func__));
+ /* We are going to be messing with random_adaptor.
+ * Exclusive lock is mandatory.
+ */
+ sx_assert(&random_adaptors_lock, SA_XLOCKED);
- rpp = malloc(sizeof(struct random_adaptors), M_ENTROPY, M_WAITOK);
- rpp->name = name;
- rpp->rsp = rsp;
+ random_adaptor_previous = random_adaptor;
- sx_xlock(&adaptors_lock);
- LIST_INSERT_HEAD(&adaptors, rpp, entries);
- sx_xunlock(&adaptors_lock);
+ random_adaptor = NULL;
+ if (TUNABLE_STR_FETCH("kern.random.active_adaptor", rngs, sizeof(rngs))) {
+ cp = rngs;
- return (0);
+ /* XXX: FIX!! (DES):
+ * - fetch tunable once, at boot
+ * - make sysctl r/w
+ * - when fetching tunable or processing a sysctl
+ * write, parse into list of strings so we don't
+ * have to do it here again and again
+ * - sysctl read should return a reconstructed string
+ */
+ while ((token = strsep(&cp, ",")) != NULL) {
+ LIST_FOREACH(rra, &random_adaptors_list, rra_entries)
+ if (strcmp(rra->rra_name, token) == 0) {
+ random_adaptor = rra->rra_ra;
+ break;
+ }
+ if (random_adaptor != NULL) {
+ printf("random: selecting requested adaptor <%s>\n",
+ random_adaptor->ra_ident);
+ break;
+ }
+ else
+ printf("random: requested adaptor <%s> not available\n",
+ token);
+ }
+ }
+
+ primax = 0;
+ if (random_adaptor == NULL) {
+ /*
+ * Fall back to the highest priority item on the available
+ * RNG list.
+ */
+ LIST_FOREACH(rrai, &random_adaptors_list, rra_entries) {
+ if (rrai->rra_ra->ra_priority >= primax) {
+ random_adaptor = rrai->rra_ra;
+ primax = rrai->rra_ra->ra_priority;
+ }
+ }
+ if (random_adaptor != NULL)
+ printf("random: selecting highest priority adaptor <%s>\n",
+ random_adaptor->ra_ident);
+ }
+
+ KASSERT(random_adaptor != NULL, ("adaptor not found"));
+
+ /* If we are changing adaptors, deinit the old and init the new. */
+ if (random_adaptor != random_adaptor_previous) {
+#ifdef RANDOM_DEBUG
+ printf("random: %s - changing from %s to %s\n", __func__,
+ (random_adaptor_previous == NULL ? "NULL" : random_adaptor_previous->ra_ident),
+ random_adaptor->ra_ident);
+#endif
+ if (random_adaptor_previous != NULL)
+ (random_adaptor_previous->ra_deinit)();
+ (random_adaptor->ra_init)();
+ }
}
-struct random_adaptor *
-random_adaptor_get(const char *name)
-{
- struct random_adaptors *rpp;
- struct random_adaptor *rsp;
- rsp = NULL;
+/* XXX: FIX!! Make sure we are not inserting a duplicate */
+void
+random_adaptor_register(const char *name, struct random_adaptor *ra)
+{
+ struct random_adaptors *rra;
- sx_slock(&adaptors_lock);
+ KASSERT(name != NULL && ra != NULL, ("invalid input to %s", __func__));
- LIST_FOREACH(rpp, &adaptors, entries)
- if (strcmp(rpp->name, name) == 0)
- rsp = rpp->rsp;
+ rra = malloc(sizeof(*rra), M_ENTROPY, M_WAITOK);
+ rra->rra_name = name;
+ rra->rra_ra = ra;
- sx_sunlock(&adaptors_lock);
+ sx_xlock(&random_adaptors_lock);
+ LIST_INSERT_HEAD(&random_adaptors_list, rra, rra_entries);
+ random_adaptor_choose();
+ sx_xunlock(&random_adaptors_lock);
- return (rsp);
+ KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
}
-/*
- * Walk a list of registered random(4) adaptors and pick the last non-selected
- * one.
- *
- * If none are selected, use yarrow if available.
- */
void
-random_adaptor_choose(struct random_adaptor **adaptor)
+random_adaptor_deregister(const char *name)
{
- char rngs[128], *token, *cp;
- struct random_adaptors *rppi, *ramax;
- unsigned primax;
+ struct random_adaptors *rra;
- KASSERT(adaptor != NULL, ("pre-conditions failed"));
+ KASSERT(name != NULL, ("invalid input to %s", __func__));
+ KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
- *adaptor = NULL;
- if (TUNABLE_STR_FETCH("kern.random.active_adaptor", rngs, sizeof(rngs))) {
- cp = rngs;
+ sx_xlock(&random_adaptors_lock);
+ LIST_FOREACH(rra, &random_adaptors_list, rra_entries)
+ if (strcmp(rra->rra_name, name) == 0) {
+ LIST_REMOVE(rra, rra_entries);
+ break;
+ }
+ random_adaptor_choose();
+ sx_xunlock(&random_adaptors_lock);
- while ((token = strsep(&cp, ",")) != NULL)
- if ((*adaptor = random_adaptor_get(token)) != NULL)
- break;
- else if (bootverbose)
- printf("%s random adaptor is not available,"
- " skipping\n", token);
+ free(rra, M_ENTROPY);
+}
+
+/* ARGSUSED */
+int
+random_adaptor_read(struct cdev *dev __unused, struct uio *uio, int flags)
+{
+ void *random_buf;
+ int c, error;
+ ssize_t nbytes;
+
+#ifdef RANDOM_DEBUG_VERBOSE
+ printf("random: %s %ld\n", __func__, uio->uio_resid);
+#endif
+
+ KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
+
+ sx_slock(&random_adaptors_lock);
+
+ /* Let the entropy source do any pre-read setup. */
+ (random_adaptor->ra_read)(NULL, 0);
+
+ /* (Un)Blocking logic */
+ error = 0;
+ while (!random_adaptor->ra_seeded()) {
+ if (flags & O_NONBLOCK) {
+ error = EWOULDBLOCK;
+ break;
+ }
+
+ /* Sleep instead of going into a spin-frenzy */
+ tsleep(&random_adaptor, PUSER | PCATCH, "block", hz/10);
+
+ /* keep tapping away at the pre-read until we seed/unblock. */
+ (random_adaptor->ra_read)(NULL, 0);
}
- primax = 0U;
- if (*adaptor == NULL) {
- /*
- * Fall back to the highest priority item on the available
- * RNG list.
- */
- sx_slock(&adaptors_lock);
+ mtx_lock(&random_read_rate_mtx);
- ramax = NULL;
- LIST_FOREACH(rppi, &adaptors, entries) {
- if (rppi->rsp->priority >= primax) {
- ramax = rppi;
- primax = rppi->rsp->priority;
- }
+ /* The read-rate stuff is a rough indication of the instantaneous read rate,
+ * used to increase the use of 'live' entropy sources when lots of reads are done.
+ */
+ nbytes = (uio->uio_resid + 32 - 1)/32; /* Round up to units of 32 */
+ random_adaptor_read_rate_cache += nbytes*32;
+ random_adaptor_read_rate_cache = MIN(random_adaptor_read_rate_cache, 32);
+
+ mtx_unlock(&random_read_rate_mtx);
+
+ if (!error) {
+
+ /* The actual read */
+
+ random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
+
+ while (uio->uio_resid && !error) {
+ c = MIN(uio->uio_resid, PAGE_SIZE);
+ (random_adaptor->ra_read)(random_buf, c);
+ error = uiomove(random_buf, c, uio);
}
- if (ramax != NULL)
- *adaptor = ramax->rsp;
- sx_sunlock(&adaptors_lock);
+ /* Let the entropy source do any post-read cleanup. */
+ (random_adaptor->ra_read)(NULL, 1);
- if (bootverbose && *adaptor)
- printf("Falling back to <%s> random adaptor\n",
- (*adaptor)->ident);
+ free(random_buf, M_ENTROPY);
}
+
+ sx_sunlock(&random_adaptors_lock);
+
+ return (error);
}
-static void
-random_adaptors_deinit(void *unused)
+int
+random_adaptor_read_rate(void)
{
+ int ret;
- sx_destroy(&adaptors_lock);
- sysctl_ctx_free(&random_clist);
+ KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
+
+ mtx_lock(&random_read_rate_mtx);
+
+ ret = random_adaptor_read_rate_cache;
+ random_adaptor_read_rate_cache = 1;
+
+ mtx_unlock(&random_read_rate_mtx);
+
+ return (ret);
}
-static int
-random_sysctl_adaptors_handler(SYSCTL_HANDLER_ARGS)
+/* ARGSUSED */
+int
+random_adaptor_write(struct cdev *dev __unused, struct uio *uio, int flags __unused)
{
- struct random_adaptors *rpp;
- int error, count;
+ int c, error = 0;
+ void *random_buf;
- count = error = 0;
+#ifdef RANDOM_DEBUG
+ printf("random: %s %zd\n", __func__, uio->uio_resid);
+#endif
- sx_slock(&adaptors_lock);
+ KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
- if (LIST_EMPTY(&adaptors))
- error = SYSCTL_OUT(req, "", 0);
- else {
- LIST_FOREACH(rpp, &adaptors, entries) {
+ sx_slock(&random_adaptors_lock);
- error = SYSCTL_OUT(req, ",", count++ ? 1 : 0);
- if (error)
- break;
+ random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
- error = SYSCTL_OUT(req, rpp->name, strlen(rpp->name));
- if (error)
- break;
- }
+ while (uio->uio_resid > 0) {
+ c = MIN(uio->uio_resid, PAGE_SIZE);
+ error = uiomove(random_buf, c, uio);
+ if (error)
+ break;
+ (random_adaptor->ra_write)(random_buf, c);
+
+ /* Introduce an annoying delay to stop swamping */
+ tsleep(&random_adaptor, PUSER | PCATCH, "block", hz/10);
}
- sx_sunlock(&adaptors_lock);
+ free(random_buf, M_ENTROPY);
+
+ sx_sunlock(&random_adaptors_lock);
return (error);
}
-static int
-random_sysctl_active_adaptor_handler(SYSCTL_HANDLER_ARGS)
+/* ARGSUSED */
+int
+random_adaptor_poll(struct cdev *dev __unused, int events, struct thread *td __unused)
{
- struct random_adaptor *rsp;
- struct random_adaptors *rpp;
- const char *name;
- int error;
- name = NULL;
- rsp = random_adaptor;
+#ifdef RANDOM_DEBUG
+ printf("random: %s\n", __func__);
+#endif
- if (rsp != NULL) {
- sx_slock(&adaptors_lock);
+ KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
- LIST_FOREACH(rpp, &adaptors, entries)
- if (rpp->rsp == rsp)
- name = rpp->name;
+ sx_slock(&random_adaptors_lock);
- sx_sunlock(&adaptors_lock);
+ if (events & (POLLIN | POLLRDNORM)) {
+ if (random_adaptor->ra_seeded())
+ events &= (POLLIN | POLLRDNORM);
+ else
+ selrecord(td, &rsel);
}
- if (rsp == NULL || name == NULL)
- error = SYSCTL_OUT(req, "", 0);
- else
- error = SYSCTL_OUT(req, name, strlen(name));
+ sx_sunlock(&random_adaptors_lock);
+
+ return (events);
+}
+
+/* This will be called by the entropy processor when it seeds itself and becomes secure */
+void
+random_adaptor_unblock(void)
+{
+
+ selwakeuppri(&rsel, PUSER);
+ wakeup(&random_adaptor);
+ printf("random: unblocking device.\n");
+
+ /* Do arc4random(9) a favour while we are about it. */
+ (void)atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_NONE, ARC4_ENTR_HAVE);
+}
+
+static int
+random_sysctl_adaptors_handler(SYSCTL_HANDLER_ARGS)
+{
+ struct random_adaptors *rra;
+ struct sbuf sbuf;
+ int error, count;
+
+ sx_slock(&random_adaptors_lock);
+ sbuf_new_for_sysctl(&sbuf, NULL, 64, req);
+ count = 0;
+ LIST_FOREACH(rra, &random_adaptors_list, rra_entries)
+ sbuf_printf(&sbuf, "%s%s(%d)",
+ (count++ ? "," : ""), rra->rra_name, rra->rra_ra->ra_priority);
+
+ error = sbuf_finish(&sbuf);
+ sbuf_delete(&sbuf);
+ sx_sunlock(&random_adaptors_lock);
return (error);
}
-static void
-random_adaptors_init(void *unused)
+static int
+random_sysctl_active_adaptor_handler(SYSCTL_HANDLER_ARGS)
+{
+ struct random_adaptors *rra;
+ struct sbuf sbuf;
+ int error;
+
+ KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
+
+ sx_slock(&random_adaptors_lock);
+ sbuf_new_for_sysctl(&sbuf, NULL, 16, req);
+ LIST_FOREACH(rra, &random_adaptors_list, rra_entries)
+ if (rra->rra_ra == random_adaptor) {
+ sbuf_cat(&sbuf, rra->rra_name);
+ break;
+ }
+ error = sbuf_finish(&sbuf);
+ sbuf_delete(&sbuf);
+ sx_sunlock(&random_adaptors_lock);
+
+ return (error);
+}
+
+void
+random_adaptors_init(void)
{
+#ifdef RANDOM_DEBUG
+ printf("random: %s\n", __func__);
+#endif
+
SYSCTL_PROC(_kern_random, OID_AUTO, adaptors,
CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
NULL, 0, random_sysctl_adaptors_handler, "A",
@@ -228,24 +416,74 @@ random_adaptors_init(void *unused)
NULL, 0, random_sysctl_active_adaptor_handler, "A",
"Active Random Number Generator Adaptor");
- sx_init(&adaptors_lock, "random_adaptors");
+ sx_init(&random_adaptors_lock, "random_adaptors");
+
+ mtx_init(&random_read_rate_mtx, "read rate mutex", NULL, MTX_DEF);
+
+ /* The dummy adaptor is not a module by itself, but part of the
+ * randomdev module.
+ */
+ random_adaptor_register("dummy", &randomdev_dummy);
+
+ live_entropy_sources_init();
}
-SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Random Number Generator");
+void
+random_adaptors_deinit(void)
+{
+
+#ifdef RANDOM_DEBUG
+ printf("random: %s\n", __func__);
+#endif
+
+ live_entropy_sources_deinit();
-SYSINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST, random_adaptors_init,
- NULL);
-SYSUNINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST,
- random_adaptors_deinit, NULL);
+ /* Don't do this! Panic will surely follow! */
+ /* random_adaptor_deregister("dummy"); */
+ mtx_destroy(&random_read_rate_mtx);
+
+ sx_destroy(&random_adaptors_lock);
+}
+
+/*
+ * First seed.
+ *
+ * NB! NB! NB!
+ * NB! NB! NB!
+ *
+ * It turns out this is bloody dangerous. I was fiddling with code elsewhere
+ * and managed to get conditions where a safe (i.e. seeded) entropy device should
+ * not have been possible. This managed to hide that by unblocking the device anyway.
+ * As crap randomness is not directly distinguishable from good randomness, this
+ * could have gone unnoticed for quite a while.
+ *
+ * NB! NB! NB!
+ * NB! NB! NB!
+ *
+ * Very luckily, the probe-time entropy is very nearly good enough to cause a
+ * first seed all of the time, and the default settings for other entropy
+ * harvesting causes a proper, safe, first seed (unblock) in short order after that.
+ *
+ * That said, the below would be useful where folks are more concerned with
+ * a quick start than with extra paranoia in a low-entropy environment.
+ *
+ * markm - October 2013.
+ */
+#ifdef RANDOM_AUTOSEED
+/* ARGSUSED */
static void
-random_adaptors_reseed(void *unused)
+random_adaptors_seed(void *unused __unused)
{
+
+ KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
+
+ sx_slock(&random_adaptors_lock);
+ random_adaptor->ra_reseed();
+ sx_sunlock(&random_adaptors_lock);
- (void)unused;
- if (random_adaptor != NULL)
- (*random_adaptor->reseed)();
arc4rand(NULL, 0, 1);
}
-SYSINIT(random_reseed, SI_SUB_INTRINSIC_POST, SI_ORDER_SECOND,
+SYSINIT(random_seed, SI_SUB_INTRINSIC_POST, SI_ORDER_LAST,
random_adaptors_reseed, NULL);
+#endif /* RANDOM_AUTOSEED */
diff --git a/sys/dev/random/random_adaptors.h b/sys/dev/random/random_adaptors.h
index 4765694..08076ce 100644
--- a/sys/dev/random/random_adaptors.h
+++ b/sys/dev/random/random_adaptors.h
@@ -29,43 +29,46 @@
#ifndef SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED
#define SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED
-#include <sys/eventhandler.h>
-
MALLOC_DECLARE(M_ENTROPY);
+typedef void random_adaptor_init_func_t(void);
+typedef void random_adaptor_deinit_func_t(void);
+typedef void random_adaptor_read_func_t(uint8_t *, u_int);
+typedef void random_adaptor_write_func_t(uint8_t *, u_int);
+typedef int random_adaptor_seeded_func_t(void);
+typedef void random_adaptor_reseed_func_t(void);
+
+struct random_adaptor {
+ const char *ra_ident;
+ int ra_priority;
+ random_adaptor_init_func_t *ra_init;
+ random_adaptor_deinit_func_t *ra_deinit;
+ random_adaptor_read_func_t *ra_read;
+ random_adaptor_write_func_t *ra_write;
+ random_adaptor_reseed_func_t *ra_reseed;
+ random_adaptor_seeded_func_t *ra_seeded;
+};
+
struct random_adaptors {
- LIST_ENTRY(random_adaptors) entries; /* list of providers */
- const char *name; /* name of random adaptor */
- struct random_adaptor *rsp;
+ LIST_ENTRY(random_adaptors) rra_entries; /* list of providers */
+ const char *rra_name; /* name of random adaptor */
+ struct random_adaptor *rra_ra;
};
-struct random_adaptor *random_adaptor_get(const char *);
-int random_adaptor_register(const char *, struct random_adaptor *);
-void random_adaptor_choose(struct random_adaptor **);
+/* Dummy "always-block" pseudo-device */
+extern struct random_adaptor randomdev_dummy;
-extern struct random_adaptor *random_adaptor;
+void random_adaptors_init(void);
+void random_adaptors_deinit(void);
-/*
- * random_adaptor's should be registered prior to
- * random module (SI_SUB_DRIVERS/SI_ORDER_MIDDLE)
- */
-#define RANDOM_ADAPTOR_MODULE(name, modevent, ver) \
- static moduledata_t name##_mod = { \
- #name, \
- modevent, \
- 0 \
- }; \
- DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, \
- SI_ORDER_SECOND); \
- MODULE_VERSION(name, ver); \
- MODULE_DEPEND(name, random, 1, 1, 1);
+void random_adaptor_register(const char *, struct random_adaptor *);
+void random_adaptor_deregister(const char *);
-typedef void (*random_adaptor_attach_hook)(void *, struct random_adaptor *);
-EVENTHANDLER_DECLARE(random_adaptor_attach, random_adaptor_attach_hook);
+int random_adaptor_read(struct cdev *, struct uio *, int);
+int random_adaptor_write(struct cdev *, struct uio *, int);
+int random_adaptor_poll(struct cdev *, int, struct thread *);
-/* kern.random sysctls */
-#ifdef SYSCTL_DECL /* from sysctl.h */
-SYSCTL_DECL(_kern_random);
-#endif /* SYSCTL_DECL */
+int random_adaptor_read_rate(void);
+void random_adaptor_unblock(void);
#endif /* SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED */
diff --git a/sys/dev/random/random_harvestq.c b/sys/dev/random/random_harvestq.c
index b7b8381..df6a853 100644
--- a/sys/dev/random/random_harvestq.c
+++ b/sys/dev/random/random_harvestq.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2000-2013 Mark R V Murray
+ * Copyright (c) 2000-2014 Mark R V Murray
* Copyright (c) 2013 Arthur Mesh
* Copyright (c) 2004 Robert N. M. Watson
* All rights reserved.
@@ -42,230 +42,293 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/random.h>
-#include <sys/selinfo.h>
+#include <sys/sbuf.h>
#include <sys/sysctl.h>
#include <sys/unistd.h>
#include <machine/cpu.h>
-#include <machine/vmparam.h>
#include <dev/random/randomdev.h>
-#include <dev/random/randomdev_soft.h>
#include <dev/random/random_adaptors.h>
#include <dev/random/random_harvestq.h>
#include <dev/random/live_entropy_sources.h>
-#include <dev/random/rwfile.h>
-#define RANDOM_FIFO_MAX 1024 /* How many events to queue up */
+/* List for the dynamic sysctls */
+static struct sysctl_ctx_list random_clist;
/*
- * The harvest mutex protects the consistency of the entropy fifos and
+ * How many events to queue up. We create this many items in
+ * an 'empty' queue, then transfer them to the 'harvest' queue with
+ * supplied junk. When used, they are transferred back to the
+ * 'empty' queue.
+ */
+#define RANDOM_FIFO_MAX 1024
+
+/*
+ * The harvest mutex protects the consistency of the entropy Fifos and
* empty fifo and other associated structures.
*/
-struct mtx harvest_mtx;
+static struct mtx harvest_mtx;
-/* Lockable FIFO queue holding entropy buffers */
-struct entropyfifo {
- int count;
- STAILQ_HEAD(harvestlist, harvest) head;
-};
+/*
+ * Lockable FIFO ring buffer holding entropy events
+ * If ring_in == ring_out,
+ * the buffer is empty.
+ * If (ring_in + 1) == ring_out (MOD RANDOM_FIFO_MAX),
+ * the buffer is full.
+ *
+ * The ring_in variable needs locking as there are multiple
+ * sources to the ring. Only the sources may change ring_in,
+ * but the consumer may examine it.
+ *
+ * The ring_out variable does not need locking as there is
+ * only one consumer. Only the consumer may change ring_out,
+ * but the sources may examine it.
+ */
+static struct entropyfifo {
+ struct harvest_event ring[RANDOM_FIFO_MAX];
+ volatile u_int ring_in;
+ volatile u_int ring_out;
+} entropyfifo;
+
+/* Round-robin destination cache. */
+u_int harvest_destination[ENTROPYSOURCE];
+
+/* Function called to process one harvested stochastic event */
+void (*harvest_process_event)(struct harvest_event *);
-/* Empty entropy buffers */
-static struct entropyfifo emptyfifo;
+/* Allow the sysadmin to select the broad category of
+ * entropy types to harvest.
+ */
+static u_int harvest_source_mask = ((1U << RANDOM_ENVIRONMENTAL_END) - 1);
-/* Harvested entropy */
-static struct entropyfifo harvestfifo;
+/* Pool count is used by anything needing to know how many entropy
+ * pools are currently being maintained.
+ * This is of use to (e.g.) the live source feed where we need to give
+ * all the pools a top-up.
+ */
+int harvest_pool_count;
/* <0 to end the kthread, 0 to let it run, 1 to flush the harvest queues */
-int random_kthread_control = 0;
+static int random_kthread_control = 0;
static struct proc *random_kthread_proc;
-#ifdef RANDOM_RWFILE
-static const char *entropy_files[] = {
- "/entropy",
- NULL
-};
-#endif
-
-/* Deal with entropy cached externally if this is present.
- * Lots of policy may eventually arrive in this function.
- * Called after / is mounted.
- */
static void
-random_harvestq_cache(void *arg __unused)
+random_kthread(void *arg __unused)
{
- uint8_t *keyfile, *data;
- size_t size, i;
-#ifdef RANDOM_RWFILE
- const char **entropy_file;
- uint8_t *zbuf;
- int error;
-#endif
-
- /* Get stuff that may have been preloaded by loader(8) */
- keyfile = preload_search_by_type("/boot/entropy");
- if (keyfile != NULL) {
- data = preload_fetch_addr(keyfile);
- size = preload_fetch_size(keyfile);
- if (data != NULL && size != 0) {
- for (i = 0; i < size; i += 16)
- random_harvestq_internal(get_cyclecount(), data + i, 16, 16, RANDOM_CACHED);
- printf("random: read %zu bytes from preloaded cache\n", size);
- bzero(data, size);
- }
- else
- printf("random: no preloaded entropy cache available\n");
- }
+ u_int maxloop, ring_out;
-#ifdef RANDOM_RWFILE
- /* Read and attempt to overwrite the entropy cache files.
- * If the file exists, can be read and then overwritten,
- * then use it. Ignore it otherwise, but print out what is
- * going on.
+ /*
+ * Process until told to stop.
+ *
+ * Locking is not needed as this is the only place we modify ring_out, and
+ * we only examine ring_in without changing it. Both of these are volatile,
+ * and this is a unique thread.
*/
- data = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
- zbuf = __DECONST(void *, zero_region);
- for (entropy_file = entropy_files; *entropy_file; entropy_file++) {
- error = randomdev_read_file(*entropy_file, data, PAGE_SIZE);
- if (error == 0) {
- printf("random: entropy cache '%s' provides %ld bytes\n", *entropy_file, (long)PAGE_SIZE);
- error = randomdev_write_file(*entropy_file, zbuf, PAGE_SIZE);
- if (error == 0) {
- printf("random: entropy cache '%s' contents used and successfully overwritten\n", *entropy_file);
- for (i = 0; i < PAGE_SIZE; i += 16)
- random_harvestq_internal(get_cyclecount(), data + i, 16, 16, RANDOM_CACHED);
- }
- else
- printf("random: entropy cache '%s' not overwritten and therefore not used; error = %d\n", *entropy_file, error);
- }
- else
- printf("random: entropy cache '%s' not present or unreadable; error = %d\n", *entropy_file, error);
- }
- bzero(data, PAGE_SIZE);
- free(data, M_ENTROPY);
-#endif
-}
-EVENTHANDLER_DEFINE(mountroot, random_harvestq_cache, NULL, 0);
+ while (random_kthread_control >= 0) {
-static void
-random_kthread(void *arg)
-{
- STAILQ_HEAD(, harvest) local_queue;
- struct harvest *event = NULL;
- int local_count;
- event_proc_f entropy_processor = arg;
+ /* Deal with events, if any. Restrict the number we do in one go. */
+ maxloop = RANDOM_FIFO_MAX;
+ while (entropyfifo.ring_out != entropyfifo.ring_in) {
- STAILQ_INIT(&local_queue);
- local_count = 0;
+ ring_out = (entropyfifo.ring_out + 1)%RANDOM_FIFO_MAX;
+ harvest_process_event(entropyfifo.ring + ring_out);
+ /* Modifying ring_out here ONLY. Sufficient for atomicity? */
+ entropyfifo.ring_out = ring_out;
- /* Process until told to stop */
- mtx_lock_spin(&harvest_mtx);
- for (; random_kthread_control >= 0;) {
-
- /*
- * Grab all the entropy events.
- * Drain entropy source records into a thread-local
- * queue for processing while not holding the mutex.
- */
- STAILQ_CONCAT(&local_queue, &harvestfifo.head);
- local_count += harvestfifo.count;
- harvestfifo.count = 0;
+ /* The ring may be filled quickly so don't loop forever. */
+ if (--maxloop)
+ break;
- /*
- * Deal with events, if any.
- * Then transfer the used events back into the empty fifo.
- */
- if (!STAILQ_EMPTY(&local_queue)) {
- mtx_unlock_spin(&harvest_mtx);
- STAILQ_FOREACH(event, &local_queue, next)
- entropy_processor(event);
- mtx_lock_spin(&harvest_mtx);
- STAILQ_CONCAT(&emptyfifo.head, &local_queue);
- emptyfifo.count += local_count;
- local_count = 0;
}
- KASSERT(local_count == 0, ("random_kthread: local_count %d",
- local_count));
-
/*
- * Do only one round of the hardware sources for now.
- * Later we'll need to make it rate-adaptive.
+ * Give the fast hardware sources a go
*/
- mtx_unlock_spin(&harvest_mtx);
- live_entropy_sources_feed(1, entropy_processor);
- mtx_lock_spin(&harvest_mtx);
+ live_entropy_sources_feed();
/*
* If a queue flush was commanded, it has now happened,
* and we can mark this by resetting the command.
+ * A negative value, however, terminates the thread.
*/
if (random_kthread_control == 1)
random_kthread_control = 0;
- /* Work done, so don't belabour the issue */
- msleep_spin_sbt(&random_kthread_control, &harvest_mtx,
- "-", SBT_1S/10, 0, C_PREL(1));
+ /* Some work is done, so give the rest of the OS a chance. */
+ tsleep_sbt(&random_kthread_control, 0, "-", SBT_1S/10, 0, C_PREL(1));
}
- mtx_unlock_spin(&harvest_mtx);
- random_set_wakeup_exit(&random_kthread_control);
+ randomdev_set_wakeup_exit(&random_kthread_control);
/* NOTREACHED */
}
void
-random_harvestq_init(event_proc_f cb)
+random_harvestq_flush(void)
+{
+
+ /* Command a entropy queue flush and wait for it to finish */
+ random_kthread_control = 1;
+ while (random_kthread_control)
+ pause("-", hz/10);
+}
+
+/* ARGSUSED */
+RANDOM_CHECK_UINT(harvestmask, 0, ((1U << RANDOM_ENVIRONMENTAL_END) - 1));
+
+/* ARGSUSED */
+static int
+random_print_harvestmask(SYSCTL_HANDLER_ARGS)
{
+ struct sbuf sbuf;
int error, i;
- struct harvest *np;
- /* Initialise the harvest fifos */
+ error = sysctl_wire_old_buffer(req, 0);
+ if (error == 0) {
+ sbuf_new_for_sysctl(&sbuf, NULL, 128, req);
+ for (i = RANDOM_ENVIRONMENTAL_END - 1; i >= 0; i--)
+ sbuf_cat(&sbuf, (harvest_source_mask & (1U << i)) ? "1" : "0");
+ error = sbuf_finish(&sbuf);
+ sbuf_delete(&sbuf);
+ }
+
+ return (error);
+}
- /* Contains the currently unused event structs. */
- STAILQ_INIT(&emptyfifo.head);
- for (i = 0; i < RANDOM_FIFO_MAX; i++) {
- np = malloc(sizeof(struct harvest), M_ENTROPY, M_WAITOK);
- STAILQ_INSERT_TAIL(&emptyfifo.head, np, next);
+static const char *(random_source_descr[]) = {
+ "CACHED",
+ "ATTACH",
+ "KEYBOARD",
+ "MOUSE",
+ "NET_TUN",
+ "NET_ETHER",
+ "NET_NG",
+ "INTERRUPT",
+ "SWI",
+ "UMA_ALLOC",
+ "", /* "ENVIRONMENTAL_END" */
+ "PURE_OCTEON",
+ "PURE_SAFE",
+ "PURE_GLXSB",
+ "PURE_UBSEC",
+ "PURE_HIFN",
+ "PURE_RDRAND",
+ "PURE_NEHEMIAH",
+ "PURE_RNDTEST",
+ /* "ENTROPYSOURCE" */
+};
+
+/* ARGSUSED */
+static int
+random_print_harvestmask_symbolic(SYSCTL_HANDLER_ARGS)
+{
+ struct sbuf sbuf;
+ int error, i;
+
+ error = sysctl_wire_old_buffer(req, 0);
+ if (error == 0) {
+ sbuf_new_for_sysctl(&sbuf, NULL, 128, req);
+ for (i = RANDOM_ENVIRONMENTAL_END - 1; i >= 0; i--) {
+ sbuf_cat(&sbuf, (i == RANDOM_ENVIRONMENTAL_END - 1) ? "" : ",");
+ sbuf_cat(&sbuf, (harvest_source_mask & (1U << i)) ? random_source_descr[i] : "");
+ }
+ error = sbuf_finish(&sbuf);
+ sbuf_delete(&sbuf);
}
- emptyfifo.count = RANDOM_FIFO_MAX;
- /* Will contain the queued-up events. */
- STAILQ_INIT(&harvestfifo.head);
- harvestfifo.count = 0;
+ return (error);
+}
+void
+random_harvestq_init(void (*event_processor)(struct harvest_event *), int poolcount)
+{
+ uint8_t *keyfile, *data;
+ int error;
+ size_t size, j;
+ struct sysctl_oid *random_sys_o;
+
+#ifdef RANDOM_DEBUG
+ printf("random: %s\n", __func__);
+#endif
+
+ random_sys_o = SYSCTL_ADD_NODE(&random_clist,
+ SYSCTL_STATIC_CHILDREN(_kern_random),
+ OID_AUTO, "harvest", CTLFLAG_RW, 0,
+ "Entropy Device Parameters");
+
+ SYSCTL_ADD_PROC(&random_clist,
+ SYSCTL_CHILDREN(random_sys_o),
+ OID_AUTO, "mask", CTLTYPE_UINT | CTLFLAG_RW,
+ &harvest_source_mask, ((1U << RANDOM_ENVIRONMENTAL_END) - 1),
+ random_check_uint_harvestmask, "IU",
+ "Entropy harvesting mask");
+
+ SYSCTL_ADD_PROC(&random_clist,
+ SYSCTL_CHILDREN(random_sys_o),
+ OID_AUTO, "mask_bin", CTLTYPE_STRING | CTLFLAG_RD,
+ NULL, 0, random_print_harvestmask, "A", "Entropy harvesting mask (printable)");
+
+ SYSCTL_ADD_PROC(&random_clist,
+ SYSCTL_CHILDREN(random_sys_o),
+ OID_AUTO, "mask_symbolic", CTLTYPE_STRING | CTLFLAG_RD,
+ NULL, 0, random_print_harvestmask_symbolic, "A", "Entropy harvesting mask (symbolic)");
+
+ /* Point to the correct event_processing function */
+ harvest_process_event = event_processor;
+
+ /* Store the pool count (used by live source feed) */
+ harvest_pool_count = poolcount;
+
+ /* Initialise the harvesting mutex and in/out indexes. */
mtx_init(&harvest_mtx, "entropy harvest mutex", NULL, MTX_SPIN);
+ entropyfifo.ring_in = entropyfifo.ring_out = 0U;
/* Start the hash/reseed thread */
- error = kproc_create(random_kthread, cb,
- &random_kthread_proc, RFHIGHPID, 0, "rand_harvestq"); /* RANDOM_CSPRNG_NAME */
+ error = kproc_create(random_kthread, NULL,
+ &random_kthread_proc, RFHIGHPID, 0, "rand_harvestq");
if (error != 0)
panic("Cannot create entropy maintenance thread.");
+
+ /* Get entropy that may have been preloaded by loader(8)
+ * and use it to pre-charge the entropy harvest queue.
+ */
+ keyfile = preload_search_by_type("/boot/entropy");
+ if (keyfile != NULL) {
+ data = preload_fetch_addr(keyfile);
+ size = preload_fetch_size(keyfile);
+ if (data != NULL && size != 0) {
+ for (j = 0; j < size; j += 16)
+ random_harvestq_internal(data + j, 16, 16, RANDOM_CACHED);
+ printf("random: read %zu bytes from preloaded cache\n", size);
+ bzero(data, size);
+ }
+ else
+ printf("random: no preloaded entropy cache\n");
+ }
+
}
void
random_harvestq_deinit(void)
{
- struct harvest *np;
- /* Destroy the harvest fifos */
- while (!STAILQ_EMPTY(&emptyfifo.head)) {
- np = STAILQ_FIRST(&emptyfifo.head);
- STAILQ_REMOVE_HEAD(&emptyfifo.head, next);
- free(np, M_ENTROPY);
- }
- emptyfifo.count = 0;
- while (!STAILQ_EMPTY(&harvestfifo.head)) {
- np = STAILQ_FIRST(&harvestfifo.head);
- STAILQ_REMOVE_HEAD(&harvestfifo.head, next);
- free(np, M_ENTROPY);
- }
- harvestfifo.count = 0;
+#ifdef RANDOM_DEBUG
+ printf("random: %s\n", __func__);
+#endif
+
+ /*
+ * Command the hash/reseed thread to end and wait for it to finish
+ */
+ random_kthread_control = -1;
+ tsleep(&random_kthread_control, 0, "term", 0);
mtx_destroy(&harvest_mtx);
+
+ sysctl_ctx_free(&random_clist);
}
/*
@@ -278,45 +341,42 @@ random_harvestq_deinit(void)
* check a few lines below. This includes the "always-on" sources
* like the Intel "rdrand" or the VIA Nehamiah "xstore" sources.
*/
+/* XXXRW: get_cyclecount() is cheap on most modern hardware, where cycle
+ * counters are built in, but on older hardware it will do a real time clock
+ * read which can be quite expensive.
+ */
void
-random_harvestq_internal(u_int64_t somecounter, const void *entropy,
- u_int count, u_int bits, enum esource origin)
+random_harvestq_internal(const void *entropy, u_int count, u_int bits,
+ enum random_entropy_source origin)
{
- struct harvest *event;
+ struct harvest_event *event;
+ u_int ring_in;
KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE,
("random_harvest_internal: origin %d invalid\n", origin));
- /* Lockless read to avoid lock operations if fifo is full. */
- if (harvestfifo.count >= RANDOM_FIFO_MAX)
+ /* Mask out unwanted sources */
+ if (!(harvest_source_mask & (1U << origin)))
return;
+ /* Lock ring_in against multi-thread contention */
mtx_lock_spin(&harvest_mtx);
-
- /*
- * On't overfill the harvest queue; this could steal all
- * our memory.
- */
- if (harvestfifo.count < RANDOM_FIFO_MAX) {
- event = STAILQ_FIRST(&emptyfifo.head);
- if (event != NULL) {
- /* Add the harvested data to the fifo */
- STAILQ_REMOVE_HEAD(&emptyfifo.head, next);
- emptyfifo.count--;
- event->somecounter = somecounter;
- event->size = count;
- event->bits = bits;
- event->source = origin;
-
- /* XXXX Come back and make this dynamic! */
- count = MIN(count, HARVESTSIZE);
- memcpy(event->entropy, entropy, count);
-
- STAILQ_INSERT_TAIL(&harvestfifo.head,
- event, next);
- harvestfifo.count++;
- }
+ ring_in = (entropyfifo.ring_in + 1)%RANDOM_FIFO_MAX;
+ if (ring_in != entropyfifo.ring_out) {
+ /* The ring is not full */
+ event = entropyfifo.ring + ring_in;
+
+ /* Stash the harvested stuff in the *event buffer */
+ count = MIN(count, HARVESTSIZE);
+ event->he_somecounter = get_cyclecount();
+ event->he_size = count;
+ event->he_bits = bits;
+ event->he_source = origin;
+ event->he_destination = harvest_destination[origin]++;
+ memcpy(event->he_entropy, entropy, count);
+ memset(event->he_entropy + count, 0, HARVESTSIZE - count);
+
+ entropyfifo.ring_in = ring_in;
}
-
mtx_unlock_spin(&harvest_mtx);
}
diff --git a/sys/dev/random/random_harvestq.h b/sys/dev/random/random_harvestq.h
index a2ac3d1..ab09a3f 100644
--- a/sys/dev/random/random_harvestq.h
+++ b/sys/dev/random/random_harvestq.h
@@ -1,4 +1,5 @@
/*-
+ * Copyright (c) 2013-2014 Mark R V Murray
* Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
* All rights reserved.
*
@@ -29,14 +30,41 @@
#ifndef SYS_DEV_RANDOM_RANDOM_HARVESTQ_H_INCLUDED
#define SYS_DEV_RANDOM_RANDOM_HARVESTQ_H_INCLUDED
-typedef void (*event_proc_f)(struct harvest *event);
+#define HARVESTSIZE 16 /* max size of each harvested entropy unit */
-void random_harvestq_init(event_proc_f);
+/* These are used to queue harvested packets of entropy. The entropy
+ * buffer size is pretty arbitrary.
+ */
+struct harvest_event {
+ uintmax_t he_somecounter; /* fast counter for clock jitter */
+ uint8_t he_entropy[HARVESTSIZE];/* some harvested entropy */
+ u_int he_size; /* harvested entropy byte count */
+ u_int he_bits; /* stats about the entropy */
+ u_int he_destination; /* destination pool of this entropy */
+ enum random_entropy_source he_source; /* origin of the entropy */
+};
+
+void random_harvestq_init(void (*)(struct harvest_event *), int);
void random_harvestq_deinit(void);
-void random_harvestq_internal(u_int64_t, const void *,
- u_int, u_int, enum esource);
+void random_harvestq_internal(const void *, u_int, u_int, enum random_entropy_source);
+
+/* Pool count is used by anything needing to know how many entropy
+ * pools are currently being maintained.
+ * This is of use to (e.g.) the live source feed where we need to give
+ * all the pools a top-up.
+ */
+extern int harvest_pool_count;
+
+/* This is in randomdev.c as it needs to be permanently in the kernel */
+void randomdev_set_wakeup_exit(void *);
+
+/* Force all currently pending queue contents to clear, and kick the software processor */
+void random_harvestq_flush(void);
+
+/* Function called to process one harvested stochastic event */
+extern void (*harvest_process_event)(struct harvest_event *);
-extern int random_kthread_control;
-extern struct mtx harvest_mtx;
+/* Round-robin destination cache. */
+extern u_int harvest_destination[ENTROPYSOURCE];
#endif /* SYS_DEV_RANDOM_RANDOM_HARVESTQ_H_INCLUDED */
diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c
index b76cb83..bc41d51 100644
--- a/sys/dev/random/randomdev.c
+++ b/sys/dev/random/randomdev.c
@@ -26,9 +26,28 @@
*
*/
+/*
+ * NOTE NOTE NOTE
+ *
+ * This file is compiled into the kernel unconditionally. Any random(4)
+ * infrastructure that needs to be in the kernel by default goes here!
+ *
+ * Except ...
+ *
+ * The adaptor code all goes into random_adaptor.c, which is also compiled
+ * the kernel by default. The module in that file is initialised before
+ * this one.
+ *
+ * Other modules must be initialised after the above two, and are
+ * software random processors which plug into random_adaptor.c.
+ *
+ */
+
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_random.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
@@ -38,196 +57,196 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/kthread.h>
#include <sys/lock.h>
-#include <sys/malloc.h>
#include <sys/module.h>
-#include <sys/mutex.h>
-#include <sys/poll.h>
-#include <sys/priv.h>
+#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/random.h>
-#include <sys/selinfo.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
#include <sys/uio.h>
#include <sys/unistd.h>
-#include <machine/bus.h>
-#include <machine/cpu.h>
-
#include <dev/random/randomdev.h>
-#include <dev/random/randomdev_soft.h>
#include <dev/random/random_adaptors.h>
#include <dev/random/random_harvestq.h>
-#include <dev/random/live_entropy_sources.h>
#define RANDOM_MINOR 0
-static d_read_t random_read;
-static d_write_t random_write;
-static d_ioctl_t random_ioctl;
-static d_poll_t random_poll;
+static d_ioctl_t randomdev_ioctl;
static struct cdevsw random_cdevsw = {
- .d_version = D_VERSION,
- .d_read = random_read,
- .d_write = random_write,
- .d_ioctl = random_ioctl,
- .d_poll = random_poll,
.d_name = "random",
+ .d_version = D_VERSION,
+ .d_read = random_adaptor_read,
+ .d_write = random_adaptor_write,
+ .d_poll = random_adaptor_poll,
+ .d_ioctl = randomdev_ioctl,
};
/* For use with make_dev(9)/destroy_dev(9). */
static struct cdev *random_dev;
+/* Set up the sysctl root node for the entropy device */
+SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Random Number Generator");
+
+MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures");
+
/* ARGSUSED */
static int
-random_read(struct cdev *dev __unused, struct uio *uio, int flag)
+randomdev_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused,
+ int flags __unused, struct thread *td __unused)
{
- int c, error = 0;
- void *random_buf;
-
- /* Blocking logic */
- if (!random_adaptor->seeded)
- error = (*random_adaptor->block)(flag);
-
- /* The actual read */
- if (!error) {
-
- random_buf = (void *)malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
+ int error = 0;
- while (uio->uio_resid > 0 && !error) {
- c = MIN(uio->uio_resid, PAGE_SIZE);
- c = (*random_adaptor->read)(random_buf, c);
- error = uiomove(random_buf, c, uio);
- }
- /* Finished reading; let the source know so it can do some
- * optional housekeeping */
- (*random_adaptor->read)(NULL, 0);
+ switch (cmd) {
+ /* Really handled in upper layer */
+ case FIOASYNC:
+ case FIONBIO:
+ break;
- free(random_buf, M_ENTROPY);
+ default:
+ error = ENOTTY;
}
return (error);
}
-/* ARGSUSED */
-static int
-random_write(struct cdev *dev __unused, struct uio *uio, int flag __unused)
+/* Helper routine to enable kproc_exit() to work while the module is
+ * being (or has been) unloaded.
+ * This routine is in this file because it is always linked into the kernel,
+ * and will thus never be unloaded. This is critical for unloadable modules
+ * that have threads.
+ */
+void
+randomdev_set_wakeup_exit(void *control)
{
- /* We used to allow this to insert userland entropy.
- * We don't any more because (1) this so-called entropy
- * is usually lousy and (b) its vaguely possible to
- * mess with entropy harvesting by overdoing a write.
- * Now we just ignore input like /dev/null does.
- */
- uio->uio_resid = 0;
-
- return (0);
+ wakeup(control);
+ kproc_exit(0);
+ /* NOTREACHED */
}
/* ARGSUSED */
static int
-random_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused,
- int flags __unused, struct thread *td __unused)
+randomdev_modevent(module_t mod __unused, int type, void *data __unused)
{
int error = 0;
- switch (cmd) {
- /* Really handled in upper layer */
- case FIOASYNC:
- case FIONBIO:
+ switch (type) {
+ case MOD_LOAD:
+ printf("random: entropy device infrastructure driver\n");
+ random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw,
+ RANDOM_MINOR, NULL, UID_ROOT, GID_WHEEL, 0644, "random");
+ make_dev_alias(random_dev, "urandom"); /* compatibility */
+ random_adaptors_init();
break;
+
+ case MOD_UNLOAD:
+ random_adaptors_deinit();
+ destroy_dev(random_dev);
+ break;
+
+ case MOD_SHUTDOWN:
+ break;
+
default:
- error = ENOTTY;
+ error = EOPNOTSUPP;
+ break;
+
}
+
return (error);
}
-/* ARGSUSED */
-static int
-random_poll(struct cdev *dev __unused, int events, struct thread *td)
-{
- int revents = 0;
+#define EARLY_2_DEV_MODULE(name, evh, arg) \
+static moduledata_t name##_mod = { \
+ #name, \
+ evh, \
+ arg \
+}; \
+DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND)
- if (events & (POLLIN | POLLRDNORM)) {
- if (random_adaptor->seeded)
- revents = events & (POLLIN | POLLRDNORM);
- else
- revents = (*random_adaptor->poll)(events, td);
- }
- return (revents);
-}
+EARLY_2_DEV_MODULE(randomdev, randomdev_modevent, NULL);
+MODULE_VERSION(randomdev, 1);
+
+/* ================
+ * Harvesting stubs
+ * ================
+ */
+/* Internal stub/fake routine for when no entropy processor is loaded.
+ * If the entropy device is not loaded, don't act on harvesting calls
+ * and just return.
+ */
+/* ARGSUSED */
static void
-random_initialize(void *p, struct random_adaptor *s)
+random_harvest_phony(const void *entropy __unused, u_int count __unused,
+ u_int bits __unused, enum random_entropy_source origin __unused)
{
- static int random_inited = 0;
-
- if (random_inited) {
- printf("random: <%s> already initialized\n",
- random_adaptor->ident);
- return;
- }
+}
- random_adaptor = s;
+/* Hold the address of the routine which is actually called */
+static void (*reap_func)(const void *, u_int, u_int, enum random_entropy_source) = random_harvest_phony;
- (s->init)();
+/* Initialise the harvester when/if it is loaded */
+void
+randomdev_init_harvester(void (*reaper)(const void *, u_int, u_int, enum random_entropy_source))
+{
- printf("random: <%s> initialized\n", s->ident);
+ reap_func = reaper;
+}
- /* Use an appropriately evil mode for those who are concerned
- * with daemons */
- random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw,
- RANDOM_MINOR, NULL, UID_ROOT, GID_WHEEL, 0666, "random");
- make_dev_alias(random_dev, "urandom"); /* compatibility */
+/* Deinitialise the harvester when/if it is unloaded */
+void
+randomdev_deinit_harvester(void)
+{
- /* mark random(4) as initialized, to avoid being called again */
- random_inited = 1;
+ reap_func = random_harvest_phony;
}
-/* ARGSUSED */
-static int
-random_modevent(module_t mod __unused, int type, void *data __unused)
+/* Entropy harvesting routine.
+ * Implemented as in indirect call to allow non-inclusion of
+ * the entropy device.
+ */
+void
+random_harvest(const void *entropy, u_int count, u_int bits, enum random_entropy_source origin)
{
- static eventhandler_tag attach_tag = NULL;
- int error = 0;
-
- switch (type) {
- case MOD_LOAD:
- random_adaptor_choose(&random_adaptor);
- if (random_adaptor == NULL) {
- printf("random: No random adaptor attached, "
- "postponing initialization\n");
- attach_tag = EVENTHANDLER_REGISTER(random_adaptor_attach,
- random_initialize, NULL, EVENTHANDLER_PRI_ANY);
- } else
- random_initialize(NULL, random_adaptor);
+ (*reap_func)(entropy, count, bits, origin);
+}
- break;
+/* ================================
+ * Internal reading stubs and fakes
+ * ================================
+ */
- case MOD_UNLOAD:
- if (random_adaptor != NULL) {
- (*random_adaptor->deinit)();
- destroy_dev(random_dev);
- }
- /* Unregister the event handler */
- if (attach_tag != NULL)
- EVENTHANDLER_DEREGISTER(random_adaptor_attach,
- attach_tag);
+/* Hold the address of the routine which is actually called */
+static u_int (*read_func)(uint8_t *, u_int) = dummy_random_read_phony;
- break;
+/* Initialise the reader when/if it is loaded */
+void
+randomdev_init_reader(u_int (*reader)(uint8_t *, u_int))
+{
- case MOD_SHUTDOWN:
- break;
+ read_func = reader;
+}
- default:
- error = EOPNOTSUPP;
- break;
+/* Deinitialise the reader when/if it is unloaded */
+void
+randomdev_deinit_reader(void)
+{
- }
- return (error);
+ read_func = dummy_random_read_phony;
}
-DEV_MODULE(random, random_modevent, NULL);
-MODULE_VERSION(random, 1);
+/* Kernel API version of read_random().
+ * Implemented as in indirect call to allow non-inclusion of
+ * the entropy device.
+ */
+int
+read_random(void *buf, int count)
+{
+
+ return ((int)(*read_func)(buf, (u_int)count));
+}
diff --git a/sys/dev/random/randomdev.h b/sys/dev/random/randomdev.h
index b87789f..4daf735 100644
--- a/sys/dev/random/randomdev.h
+++ b/sys/dev/random/randomdev.h
@@ -35,28 +35,33 @@
typedef void random_init_func_t(void);
typedef void random_deinit_func_t(void);
-typedef int random_block_func_t(int);
-typedef int random_read_func_t(void *, int);
-typedef int random_poll_func_t(int, struct thread *);
-typedef void random_reseed_func_t(void);
-
-struct random_adaptor {
- struct selinfo rsel;
- const char *ident;
- int seeded;
- unsigned priority;
- random_init_func_t *init;
- random_deinit_func_t *deinit;
- random_block_func_t *block;
- random_read_func_t *read;
- random_poll_func_t *poll;
- random_reseed_func_t *reseed;
-};
-
-struct random_hardware_source {
- const char *ident;
- enum esource source;
- random_read_func_t *read;
-};
+
+void randomdev_init_harvester(void (*)(const void *, u_int, u_int, enum random_entropy_source));
+void randomdev_init_reader(u_int (*)(uint8_t *, u_int));
+void randomdev_deinit_harvester(void);
+void randomdev_deinit_reader(void);
+
+/* Stub/fake routines for when no entropy processor is loaded */
+extern u_int dummy_random_read_phony(uint8_t *, u_int);
+
+/* kern.random sysctls */
+#ifdef SYSCTL_DECL /* from sysctl.h */
+SYSCTL_DECL(_kern_random);
+
+/* If this was C++, the macro below would be a template */
+#define RANDOM_CHECK_UINT(name, min, max) \
+static int \
+random_check_uint_##name(SYSCTL_HANDLER_ARGS) \
+{ \
+ if (oidp->oid_arg1 != NULL) { \
+ if (*(u_int *)(oidp->oid_arg1) <= (min)) \
+ *(u_int *)(oidp->oid_arg1) = (min); \
+ else if (*(u_int *)(oidp->oid_arg1) > (max)) \
+ *(u_int *)(oidp->oid_arg1) = (max); \
+ } \
+ return (sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, \
+ req)); \
+}
+#endif /* SYSCTL_DECL */
#endif
diff --git a/sys/dev/random/randomdev_soft.c b/sys/dev/random/randomdev_soft.c
index 0929704..61cdf35 100644
--- a/sys/dev/random/randomdev_soft.c
+++ b/sys/dev/random/randomdev_soft.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2000-2013 Mark R V Murray
+ * Copyright (c) 2000-2014 Mark R V Murray
* Copyright (c) 2004 Robert N. M. Watson
* All rights reserved.
*
@@ -26,6 +26,16 @@
*
*/
+/*
+ * This is the loadable infrastructure base file for software CSPRNG
+ * drivers such as Yarrow or Fortuna.
+ *
+ * It is anticipated that one instance of this file will be used
+ * for _each_ invocation of a CSPRNG, but with different #defines
+ * set. See below.
+ *
+ */
+
#include "opt_random.h"
#if !defined(RANDOM_YARROW) && !defined(RANDOM_FORTUNA)
@@ -33,15 +43,13 @@
#elif defined(RANDOM_YARROW) && defined(RANDOM_FORTUNA)
#error "Must define either RANDOM_YARROW or RANDOM_FORTUNA"
#endif
-#if defined(RANDOM_FORTUNA)
-#error "Fortuna is not yet implemented"
-#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/conf.h>
#include <sys/fcntl.h>
#include <sys/kernel.h>
#include <sys/lock.h>
@@ -50,14 +58,9 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/poll.h>
#include <sys/random.h>
-#include <sys/selinfo.h>
#include <sys/sysctl.h>
-#include <sys/uio.h>
#include <sys/unistd.h>
-#include <machine/bus.h>
-#include <machine/cpu.h>
-
#include <dev/random/randomdev.h>
#include <dev/random/randomdev_soft.h>
#include <dev/random/random_harvestq.h>
@@ -69,111 +72,44 @@ __FBSDID("$FreeBSD$");
#include <dev/random/fortuna.h>
#endif
-
-static int randomdev_poll(int event, struct thread *td);
-static int randomdev_block(int flag);
-static void randomdev_flush_reseed(void);
-
+static struct random_adaptor random_soft_processor = {
#if defined(RANDOM_YARROW)
-static struct random_adaptor random_context = {
- .ident = "Software, Yarrow",
- .init = randomdev_init,
- .deinit = randomdev_deinit,
- .block = randomdev_block,
- .read = random_yarrow_read,
- .poll = randomdev_poll,
- .reseed = randomdev_flush_reseed,
- .seeded = 0, /* This will be seeded during entropy processing */
- .priority = 90, /* High priority, so top of the list. Fortuna may still win. */
-};
-#define RANDOM_MODULE_NAME yarrow
#define RANDOM_CSPRNG_NAME "yarrow"
+ .ra_ident = "Yarrow",
+ .ra_priority = 90, /* High priority, so top of the list. Fortuna may still win. */
+ .ra_read = random_yarrow_read,
+ .ra_write = random_yarrow_write,
+ .ra_reseed = random_yarrow_reseed,
+ .ra_seeded = random_yarrow_seeded,
#endif
-
#if defined(RANDOM_FORTUNA)
-static struct random_adaptor random_context = {
- .ident = "Software, Fortuna",
- .init = randomdev_init,
- .deinit = randomdev_deinit,
- .block = randomdev_block,
- .read = random_fortuna_read,
- .poll = randomdev_poll,
- .reseed = randomdev_flush_reseed,
- .seeded = 0, /* This will be excplicitly seeded at startup when secured */
- .priority = 100, /* High priority, so top of the list. Beat Yarrow. */
-};
-#define RANDOM_MODULE_NAME fortuna
#define RANDOM_CSPRNG_NAME "fortuna"
+ .ra_ident = "Fortuna",
+ .ra_priority = 100, /* High priority, so top of the list. Beat Yarrow. */
+ .ra_read = random_fortuna_read,
+ .ra_write = random_fortuna_write,
+ .ra_reseed = random_fortuna_reseed,
+ .ra_seeded = random_fortuna_seeded,
#endif
-
-TUNABLE_INT("kern.random.sys.seeded", &random_context.seeded);
-
-/* List for the dynamic sysctls */
-static struct sysctl_ctx_list random_clist;
-
-/* ARGSUSED */
-static int
-random_check_boolean(SYSCTL_HANDLER_ARGS)
-{
- if (oidp->oid_arg1 != NULL && *(u_int *)(oidp->oid_arg1) != 0)
- *(u_int *)(oidp->oid_arg1) = 1;
- return (sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req));
-}
+ .ra_init = randomdev_init,
+ .ra_deinit = randomdev_deinit,
+};
void
randomdev_init(void)
{
- struct sysctl_oid *random_sys_o, *random_sys_harvest_o;
#if defined(RANDOM_YARROW)
- random_yarrow_init_alg(&random_clist);
+ random_yarrow_init_alg();
+ random_harvestq_init(random_yarrow_process_event, 2);
#endif
#if defined(RANDOM_FORTUNA)
- random_fortuna_init_alg(&random_clist);
+ random_fortuna_init_alg();
+ random_harvestq_init(random_fortuna_process_event, 32);
#endif
- random_sys_o = SYSCTL_ADD_NODE(&random_clist,
- SYSCTL_STATIC_CHILDREN(_kern_random),
- OID_AUTO, "sys", CTLFLAG_RW, 0,
- "Entropy Device Parameters");
-
- SYSCTL_ADD_PROC(&random_clist,
- SYSCTL_CHILDREN(random_sys_o),
- OID_AUTO, "seeded", CTLTYPE_INT | CTLFLAG_RW,
- &random_context.seeded, 0, random_check_boolean, "I",
- "Seeded State");
-
- random_sys_harvest_o = SYSCTL_ADD_NODE(&random_clist,
- SYSCTL_CHILDREN(random_sys_o),
- OID_AUTO, "harvest", CTLFLAG_RW, 0,
- "Entropy Sources");
-
- SYSCTL_ADD_PROC(&random_clist,
- SYSCTL_CHILDREN(random_sys_harvest_o),
- OID_AUTO, "ethernet", CTLTYPE_INT | CTLFLAG_RW,
- &harvest.ethernet, 1, random_check_boolean, "I",
- "Harvest NIC entropy");
- SYSCTL_ADD_PROC(&random_clist,
- SYSCTL_CHILDREN(random_sys_harvest_o),
- OID_AUTO, "point_to_point", CTLTYPE_INT | CTLFLAG_RW,
- &harvest.point_to_point, 1, random_check_boolean, "I",
- "Harvest serial net entropy");
- SYSCTL_ADD_PROC(&random_clist,
- SYSCTL_CHILDREN(random_sys_harvest_o),
- OID_AUTO, "interrupt", CTLTYPE_INT | CTLFLAG_RW,
- &harvest.interrupt, 1, random_check_boolean, "I",
- "Harvest IRQ entropy");
- SYSCTL_ADD_PROC(&random_clist,
- SYSCTL_CHILDREN(random_sys_harvest_o),
- OID_AUTO, "swi", CTLTYPE_INT | CTLFLAG_RW,
- &harvest.swi, 1, random_check_boolean, "I",
- "Harvest SWI entropy");
-
- random_harvestq_init(random_process_event);
-
/* Register the randomness harvesting routine */
- randomdev_init_harvester(random_harvestq_internal,
- random_context.read);
+ randomdev_init_harvester(random_harvestq_internal);
}
void
@@ -182,118 +118,56 @@ randomdev_deinit(void)
/* Deregister the randomness harvesting routine */
randomdev_deinit_harvester();
- /*
- * Command the hash/reseed thread to end and wait for it to finish
- */
- random_kthread_control = -1;
- tsleep((void *)&random_kthread_control, 0, "term", 0);
-
#if defined(RANDOM_YARROW)
random_yarrow_deinit_alg();
#endif
#if defined(RANDOM_FORTUNA)
random_fortuna_deinit_alg();
#endif
-
- sysctl_ctx_free(&random_clist);
-}
-
-void
-randomdev_unblock(void)
-{
- if (!random_context.seeded) {
- selwakeuppri(&random_context.rsel, PUSER);
- wakeup(&random_context);
- printf("random: unblocking device.\n");
- random_context.seeded = 1;
- }
- /* Do arc4random(9) a favour while we are about it. */
- (void)atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_NONE,
- ARC4_ENTR_HAVE);
}
+/* ARGSUSED */
static int
-randomdev_poll(int events, struct thread *td)
+randomdev_soft_modevent(module_t mod __unused, int type, void *unused __unused)
{
- int revents = 0;
-
- mtx_lock(&random_reseed_mtx);
+ int error = 0;
- if (random_context.seeded)
- revents = events & (POLLIN | POLLRDNORM);
- else
- selrecord(td, &random_context.rsel);
+ switch (type) {
+ case MOD_LOAD:
+ printf("random: SOFT: %s init()\n", RANDOM_CSPRNG_NAME);
+ random_adaptor_register(RANDOM_CSPRNG_NAME, &random_soft_processor);
+ break;
- mtx_unlock(&random_reseed_mtx);
- return (revents);
-}
+ case MOD_UNLOAD:
+ random_adaptor_deregister(RANDOM_CSPRNG_NAME);
+ break;
-static int
-randomdev_block(int flag)
-{
- int error = 0;
+ case MOD_SHUTDOWN:
+ break;
- mtx_lock(&random_reseed_mtx);
+ default:
+ error = EOPNOTSUPP;
+ break;
- /* Blocking logic */
- while (!random_context.seeded && !error) {
- if (flag & O_NONBLOCK)
- error = EWOULDBLOCK;
- else {
- printf("random: blocking on read.\n");
- error = msleep(&random_context,
- &random_reseed_mtx,
- PUSER | PCATCH, "block", 0);
- }
}
- mtx_unlock(&random_reseed_mtx);
-
return (error);
}
-/* Helper routine to perform explicit reseeds */
-static void
-randomdev_flush_reseed(void)
-{
- /* Command a entropy queue flush and wait for it to finish */
- random_kthread_control = 1;
- while (random_kthread_control)
- pause("-", hz / 10);
+#define MID_DEV_MODULE(name, evh, arg) \
+static moduledata_t name##_mod = { \
+ #name, \
+ evh, \
+ arg \
+}; \
+DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE)
#if defined(RANDOM_YARROW)
- /* This ultimately calls randomdev_unblock() */
- random_yarrow_reseed();
+MID_DEV_MODULE(yarrow, randomdev_soft_modevent, NULL);
+MODULE_VERSION(yarrow, 1);
+MODULE_DEPEND(yarrow, random_adaptors, 1, 1, 1);
#endif
#if defined(RANDOM_FORTUNA)
- /* This ultimately calls randomdev_unblock() */
- random_fortuna_reseed();
+MID_DEV_MODULE(fortuna, randomdev_soft_modevent, NULL);
+MODULE_VERSION(fortuna, 1);
+MODULE_DEPEND(fortuna, random_adaptors, 1, 1, 1);
#endif
-}
-
-static int
-randomdev_modevent(module_t mod __unused, int type, void *unused __unused)
-{
-
- switch (type) {
- case MOD_LOAD:
- random_adaptor_register(RANDOM_CSPRNG_NAME, &random_context);
- /*
- * For statically built kernels that contain both device
- * random and options PADLOCK_RNG/RDRAND_RNG/etc..,
- * this event handler will do nothing, since the random
- * driver-specific handlers are loaded after these HW
- * consumers, and hence hasn't yet registered for this event.
- *
- * In case where both the random driver and RNG's are built
- * as seperate modules, random.ko is loaded prior to *_rng.ko's
- * (by dependency). This event handler is there to delay
- * creation of /dev/{u,}random and attachment of this *_rng.ko.
- */
- EVENTHANDLER_INVOKE(random_adaptor_attach, &random_context);
- return (0);
- }
-
- return (EINVAL);
-}
-
-RANDOM_ADAPTOR_MODULE(RANDOM_MODULE_NAME, randomdev_modevent, 1);
diff --git a/sys/dev/random/randomdev_soft.h b/sys/dev/random/randomdev_soft.h
index cbee779..e814de6 100644
--- a/sys/dev/random/randomdev_soft.h
+++ b/sys/dev/random/randomdev_soft.h
@@ -29,58 +29,11 @@
#ifndef SYS_DEV_RANDOM_RANDOMDEV_SOFT_H_INCLUDED
#define SYS_DEV_RANDOM_RANDOMDEV_SOFT_H_INCLUDED
-/* This header contains only those definitions that are global
- * and harvester-specific for the entropy processor
+/* This header contains only those definitions that are
+ * specific to the entropy processor
*/
-/* #define ENTROPYSOURCE nn entropy sources (actually classes)
- * This is properly defined in
- * an enum in sys/random.h
- */
-
-/* The ring size _MUST_ be a power of 2 */
-#define HARVEST_RING_SIZE 1024 /* harvest ring buffer size */
-#define HARVEST_RING_MASK (HARVEST_RING_SIZE - 1)
-
-#define HARVESTSIZE 16 /* max size of each harvested entropy unit */
-
-/* These are used to queue harvested packets of entropy. The entropy
- * buffer size is pretty arbitrary.
- */
-struct harvest {
- uintmax_t somecounter; /* fast counter for clock jitter */
- uint8_t entropy[HARVESTSIZE]; /* the harvested entropy */
- u_int size, bits; /* stats about the entropy */
- enum esource source; /* origin of the entropy */
- STAILQ_ENTRY(harvest) next; /* next item on the list */
-};
-
void randomdev_init(void);
void randomdev_deinit(void);
-void randomdev_init_harvester(void (*)(u_int64_t, const void *, u_int,
- u_int, enum esource), int (*)(void *, int));
-void randomdev_deinit_harvester(void);
-
-void random_set_wakeup_exit(void *);
-void random_process_event(struct harvest *event);
-void randomdev_unblock(void);
-
-extern struct mtx random_reseed_mtx;
-
-/* If this was C++, the macro below would be a template */
-#define RANDOM_CHECK_UINT(name, min, max) \
-static int \
-random_check_uint_##name(SYSCTL_HANDLER_ARGS) \
-{ \
- if (oidp->oid_arg1 != NULL) { \
- if (*(u_int *)(oidp->oid_arg1) <= (min)) \
- *(u_int *)(oidp->oid_arg1) = (min); \
- else if (*(u_int *)(oidp->oid_arg1) > (max)) \
- *(u_int *)(oidp->oid_arg1) = (max); \
- } \
- return (sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, \
- req)); \
-}
-
#endif
diff --git a/sys/dev/random/rwfile.c b/sys/dev/random/rwfile.c
deleted file mode 100644
index 9b38957..0000000
--- a/sys/dev/random/rwfile.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*-
- * Copyright (c) 2013 Mark R V Murray
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer
- * in this position and unchanged.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include "opt_random.h"
-
-#ifdef RANDOM_RWFILE
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/proc.h>
-#include <sys/namei.h>
-#include <sys/fcntl.h>
-#include <sys/vnode.h>
-
-#include <dev/random/rwfile.h>
-
-int
-randomdev_read_file(const char *filename, void *buf, size_t length)
-{
- struct nameidata nd;
- struct thread* td = curthread;
- int error;
- ssize_t resid;
- int flags;
-
- NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, td);
- flags = FREAD;
- error = vn_open(&nd, &flags, 0, NULL);
- if (error == 0) {
- NDFREE(&nd, NDF_ONLY_PNBUF);
- if (nd.ni_vp->v_type != VREG)
- error = ENOEXEC;
- else
- error = vn_rdwr(UIO_READ, nd.ni_vp, buf, length, 0, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, td);
- VOP_UNLOCK(nd.ni_vp, 0);
- vn_close(nd.ni_vp, FREAD, td->td_ucred, td);
- }
-
- return (error);
-}
-
-int
-randomdev_write_file(const char *filename, void *buf, size_t length)
-{
- struct nameidata nd;
- struct thread* td = curthread;
- int error;
- ssize_t resid;
- int flags;
-
- NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, td);
- flags = FWRITE | O_CREAT | O_TRUNC;
- error = vn_open(&nd, &flags, 0, NULL);
- if (error == 0) {
- NDFREE(&nd, NDF_ONLY_PNBUF);
- if (nd.ni_vp->v_type != VREG)
- error = ENOEXEC;
- else
- error = vn_rdwr(UIO_WRITE, nd.ni_vp, buf, length, 0, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, td);
-
- VOP_UNLOCK(nd.ni_vp, 0);
- vn_close(nd.ni_vp, FREAD, td->td_ucred, td);
- }
-
- return (error);
-}
-
-#endif
diff --git a/sys/dev/random/uint128.h b/sys/dev/random/uint128.h
new file mode 100644
index 0000000..b2cc1e0
--- /dev/null
+++ b/sys/dev/random/uint128.h
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 2014 Mark R V Murray
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef SYS_DEV_RANDOM_UINT128_H_INCLUDED
+#define SYS_DEV_RANDOM_UINT128_H_INCLUDED
+
+/* This whole thing is a crock :-(
+ *
+ * Everyone knows you always need the __uint128_t types!
+ */
+
+#ifdef __SIZEOF_INT128__
+typedef __uint128_t uint128_t;
+#else
+typedef uint64_t uint128_t[2];
+#endif
+
+static __inline void
+uint128_clear(uint128_t *big_uint)
+{
+#ifdef __SIZEOF_INT128__
+ (*big_uint) = 0ULL;
+#else
+ (*big_uint)[0] = (*big_uint)[1] = 0UL;
+#endif
+}
+
+static __inline void
+uint128_increment(uint128_t *big_uint)
+{
+#ifdef __SIZEOF_INT128__
+ (*big_uint)++;
+#else
+ (*big_uint)[0]++;
+ if ((*big_uint)[0] == 0UL)
+ (*big_uint)[1]++;
+#endif
+}
+
+static __inline int
+uint128_is_zero(uint128_t big_uint)
+{
+#ifdef __SIZEOF_INT128__
+ return (big_uint == 0ULL);
+#else
+ return (big_uint[0] == 0UL && big_uint[1] == 0UL);
+#endif
+}
+
+#endif /* SYS_DEV_RANDOM_UINT128_H_INCLUDED */
diff --git a/sys/dev/random/unit_test.c b/sys/dev/random/unit_test.c
new file mode 100644
index 0000000..32b3363
--- /dev/null
+++ b/sys/dev/random/unit_test.c
@@ -0,0 +1,257 @@
+/*-
+ * Copyright (c) 2000-2013 Mark R V Murray
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ Build this by going:
+
+cc -g -O0 -pthread -DRANDOM_<alg> -DRANDOM_DEBUG -I../.. -lstdthreads -Wall \
+ unit_test.c \
+ yarrow.c \
+ fortuna.c \
+ hash.c \
+ ../../crypto/rijndael/rijndael-api-fst.c \
+ ../../crypto/rijndael/rijndael-alg-fst.c \
+ ../../crypto/sha2/sha2.c \
+ -o unit_test
+./unit_test
+
+Where <alg> is YARROW or FORTUNA.
+*/
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <threads.h>
+#include <unistd.h>
+
+#include "unit_test.h"
+
+#ifdef RANDOM_YARROW
+#include "dev/random/yarrow.h"
+#endif
+#ifdef RANDOM_FORTUNA
+#include "dev/random/fortuna.h"
+#endif
+
+#define NUM_THREADS 3
+
+static volatile int stopseeding = 0;
+
+void
+random_adaptor_unblock(void)
+{
+
+#if 0
+ if (mtx_trylock(&random_reseed_mtx) == thrd_busy)
+ printf("Mutex held. Good.\n");
+ else {
+ printf("Mutex not held. PANIC!!\n");
+ thrd_exit(0);
+ }
+#endif
+ printf("random: unblocking device.\n");
+}
+
+static int
+RunHarvester(void *arg __unused)
+{
+ int i, r;
+ struct harvest_event e;
+
+ for (i = 0; ; i++) {
+ if (stopseeding)
+ break;
+ if (i % 1000 == 0)
+ printf("Harvest: %d\n", i);
+ r = random()%10;
+ e.he_somecounter = i;
+ *((uint64_t *)e.he_entropy) = random();
+ e.he_size = 8;
+ e.he_bits = random()%4;
+ e.he_destination = i;
+ e.he_source = (i + 3)%7;
+ e.he_next = NULL;
+#ifdef RANDOM_YARROW
+ random_yarrow_process_event(&e);
+#endif
+#ifdef RANDOM_FORTUNA
+ random_fortuna_process_event(&e);
+#endif
+ usleep(r);
+ }
+
+ printf("Thread #0 ends\n");
+
+ thrd_exit(0);
+
+ return (0);
+}
+
+static int
+WriteCSPRNG(void *threadid)
+{
+ uint8_t *buf;
+ int i;
+
+ printf("Thread #1 starts\n");
+
+ for (i = 0; ; i++) {
+ if (stopseeding)
+ break;
+ buf = malloc(4096);
+ if (i % 1000 == 0)
+ printf("Thread write 1 - %d\n", i);
+ if (buf != NULL) {
+#ifdef RANDOM_YARROW
+ random_yarrow_write(buf, i);
+#endif
+#ifdef RANDOM_FORTUNA
+ random_fortuna_write(buf, i);
+#endif
+ free(buf);
+ }
+ usleep(1000000);
+ }
+
+ printf("Thread #1 ends\n");
+
+ thrd_exit(0);
+
+ return (0);
+}
+
+static int
+ReadCSPRNG(void *threadid)
+{
+ size_t tid;
+ uint8_t *buf;
+ int i;
+
+ tid = (size_t)threadid;
+ printf("Thread #%zd starts\n", tid);
+
+#ifdef RANDOM_YARROW
+ while (!random_yarrow_seeded())
+#endif
+#ifdef RANDOM_FORTUNA
+ while (!random_fortuna_seeded())
+#endif
+ {
+#ifdef RANDOM_YARROW
+ random_yarrow_read(NULL, 0);
+ random_yarrow_read(NULL, 1);
+#endif
+#ifdef RANDOM_FORTUNA
+ random_fortuna_read(NULL, 0);
+ random_fortuna_read(NULL, 1);
+#endif
+ usleep(100);
+ }
+
+ for (i = 0; i < 100000; i++) {
+ buf = malloc(i);
+ if (i % 1000 == 0)
+ printf("Thread read %zd - %d %p\n", tid, i, buf);
+ if (buf != NULL) {
+#ifdef RANDOM_YARROW
+ random_yarrow_read(NULL, 0);
+ random_yarrow_read(buf, i);
+ random_yarrow_read(NULL, 1);
+#endif
+#ifdef RANDOM_FORTUNA
+ random_fortuna_read(NULL, 0);
+ random_fortuna_read(buf, i);
+ random_fortuna_read(NULL, 1);
+#endif
+#if 0
+ {
+ int j;
+
+ for (j = 0; j < i; j++) {
+ printf(" %02X", buf[j]);
+ if (j % 32 == 31 || j == i - 1)
+ printf("\n");
+ }
+ }
+#endif
+ free(buf);
+ }
+ usleep(100);
+ }
+
+ printf("Thread #%zd ends\n", tid);
+
+ thrd_exit(0);
+
+ return (0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ thrd_t threads[NUM_THREADS];
+ int rc;
+ long t;
+
+#ifdef RANDOM_YARROW
+ random_yarrow_init_alg();
+#endif
+#ifdef RANDOM_FORTUNA
+ random_fortuna_init_alg();
+#endif
+
+ for (t = 0; t < NUM_THREADS; t++) {
+ printf("In main: creating thread %ld\n", t);
+ rc = thrd_create(&threads[t], (t == 0 ? RunHarvester : (t == 1 ? WriteCSPRNG : ReadCSPRNG)), t);
+ if (rc != thrd_success) {
+ printf("ERROR; return code from thrd_create() is %d\n", rc);
+ exit(-1);
+ }
+ }
+
+ for (t = 2; t < NUM_THREADS; t++)
+ thrd_join(threads[t], &rc);
+
+ stopseeding = 1;
+
+ thrd_join(threads[1], &rc);
+ thrd_join(threads[0], &rc);
+
+#ifdef RANDOM_YARROW
+ random_yarrow_deinit_alg();
+#endif
+#ifdef RANDOM_FORTUNA
+ random_fortuna_deinit_alg();
+#endif
+
+ /* Last thing that main() should do */
+ thrd_exit(0);
+
+ return (0);
+}
diff --git a/sys/dev/random/unit_test.h b/sys/dev/random/unit_test.h
new file mode 100644
index 0000000..9fc0931
--- /dev/null
+++ b/sys/dev/random/unit_test.h
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 2013 Mark R V Murray
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+
+#ifndef UNIT_TEST_H_INCLUDED
+#define UNIT_TEST_H_INCLUDED
+
+void random_adaptor_unblock(void);
+
+static __inline uint64_t
+get_cyclecount(void)
+{
+
+ /* Shaddup! */
+ return (4ULL);
+}
+
+// #define PAGE_SIZE 4096
+#define HARVESTSIZE 16
+
+enum random_entropy_source {
+ RANDOM_START = 0,
+ RANDOM_CACHED = 0,
+ ENTROPYSOURCE = 32
+};
+
+struct harvest_event {
+ uintmax_t he_somecounter; /* fast counter for clock jitter */
+ uint8_t he_entropy[HARVESTSIZE];/* some harvested entropy */
+ u_int he_size; /* harvested entropy byte count */
+ u_int he_bits; /* stats about the entropy */
+ u_int he_destination; /* destination pool of this entropy */
+ enum random_entropy_source he_source; /* origin of the entropy */
+ void * he_next; /* next item on the list */
+};
+
+struct sysctl_ctx_list;
+
+#define CTASSERT(x) _Static_assert(x, "compile-time assertion failed")
+#define KASSERT(exp,msg) do { \
+ if (!(exp)) { \
+ printf msg; \
+ exit(0); \
+ } \
+} while (0)
+
+#endif /* UNIT_TEST_H_INCLUDED */
diff --git a/sys/dev/random/yarrow.c b/sys/dev/random/yarrow.c
index 1cfa373..a8da20a 100644
--- a/sys/dev/random/yarrow.c
+++ b/sys/dev/random/yarrow.c
@@ -28,6 +28,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#ifdef _KERNEL
#include "opt_random.h"
#include <sys/param.h>
@@ -39,197 +40,280 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#include <sys/systm.h>
+#include <machine/cpu.h>
+
#include <crypto/rijndael/rijndael-api-fst.h>
#include <crypto/sha2/sha2.h>
#include <dev/random/hash.h>
+#include <dev/random/randomdev.h>
#include <dev/random/random_adaptors.h>
-#include <dev/random/randomdev_soft.h>
+#include <dev/random/random_harvestq.h>
+#include <dev/random/uint128.h>
+#include <dev/random/yarrow.h>
+#else /* !_KERNEL */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <threads.h>
+
+#include "unit_test.h"
+
+#include <crypto/rijndael/rijndael-api-fst.h>
+#include <crypto/sha2/sha2.h>
+
+#include <dev/random/hash.h>
+#include <dev/random/randomdev.h>
+#include <dev/random/uint128.h>
#include <dev/random/yarrow.h>
+#endif /* _KERNEL */
+
+#if !defined(RANDOM_YARROW) && !defined(RANDOM_FORTUNA)
+#define RANDOM_YARROW
+#elif defined(RANDOM_YARROW) && defined(RANDOM_FORTUNA)
+#error "Must define either RANDOM_YARROW or RANDOM_FORTUNA"
+#endif
+
+#if defined(RANDOM_YARROW)
#define TIMEBIN 16 /* max value for Pt/t */
#define FAST 0
#define SLOW 1
+/* This algorithm (and code) presumes that KEYSIZE is twice as large as BLOCKSIZE */
+CTASSERT(BLOCKSIZE == sizeof(uint128_t));
+CTASSERT(KEYSIZE == 2*BLOCKSIZE);
+
/* This is the beastie that needs protecting. It contains all of the
* state that we are excited about.
* Exactly one is instantiated.
*/
-static struct random_state {
+static struct yarrow_state {
union {
uint8_t byte[BLOCKSIZE];
- uint64_t qword[BLOCKSIZE/sizeof(uint64_t)];
- } counter; /* C */
- struct randomdev_key key; /* K */
- u_int gengateinterval; /* Pg */
- u_int bins; /* Pt/t */
- u_int outputblocks; /* count output blocks for gates */
- u_int slowoverthresh; /* slow pool overthreshhold reseed count */
+ uint128_t whole;
+ } counter; /* C */
+ struct randomdev_key key; /* K */
+ u_int gengateinterval; /* Pg */
+ u_int bins; /* Pt/t */
+ u_int outputblocks; /* count output blocks for gates */
+ u_int slowoverthresh; /* slow pool overthreshhold reseed count */
struct pool {
struct source {
u_int bits; /* estimated bits of entropy */
- } source[ENTROPYSOURCE];
- u_int thresh; /* pool reseed threshhold */
+ } source[ENTROPYSOURCE];/* ... per source */
+ u_int thresh; /* pool reseed threshhold */
struct randomdev_hash hash; /* accumulated entropy */
- } pool[2]; /* pool[0] is fast, pool[1] is slow */
- u_int which; /* toggle - sets the current insertion pool */
-} random_state;
+ } pool[2]; /* pool[0] is fast, pool[1] is slow */
+ int seeded;
+
+ struct start_cache {
+ uint8_t junk[KEYSIZE];
+ struct randomdev_hash hash;
+ } start_cache;
+} yarrow_state;
+/* The random_reseed_mtx mutex protects seeding and polling/blocking. */
+static mtx_t random_reseed_mtx;
+
+#ifdef _KERNEL
+static struct sysctl_ctx_list random_clist;
RANDOM_CHECK_UINT(gengateinterval, 4, 64);
RANDOM_CHECK_UINT(bins, 2, 16);
RANDOM_CHECK_UINT(fastthresh, (BLOCKSIZE*8)/4, (BLOCKSIZE*8)); /* Bit counts */
RANDOM_CHECK_UINT(slowthresh, (BLOCKSIZE*8)/4, (BLOCKSIZE*8)); /* Bit counts */
RANDOM_CHECK_UINT(slowoverthresh, 1, 5);
+#else /* !_KERNEL */
+static u_int harvest_destination[ENTROPYSOURCE];
+#endif /* _KERNEL */
static void generator_gate(void);
static void reseed(u_int);
-/* The reseed thread mutex */
-struct mtx random_reseed_mtx;
-
-/* 128-bit C = 0 */
-/* Nothing to see here, folks, just an ugly mess. */
-static void
-clear_counter(void)
-{
- random_state.counter.qword[0] = 0UL;
- random_state.counter.qword[1] = 0UL;
-}
-
-/* 128-bit C = C + 1 */
-/* Nothing to see here, folks, just an ugly mess. */
-/* TODO: Make a Galois counter instead? */
-static void
-increment_counter(void)
-{
- random_state.counter.qword[0]++;
- if (!random_state.counter.qword[0])
- random_state.counter.qword[1]++;
-}
-
-/* Process a single stochastic event off the harvest queue */
void
-random_process_event(struct harvest *event)
+random_yarrow_init_alg(void)
{
- u_int pl, overthreshhold[2];
- struct source *source;
- enum esource src;
-
-#if 0
- /* Do this better with DTrace */
- {
- int i;
-
- printf("Harvest:%16jX ", event->somecounter);
- for (i = 0; i < event->size; i++)
- printf("%02X", event->entropy[i]);
- for (; i < 16; i++)
- printf(" ");
- printf(" %2d %2d %02X\n", event->size, event->bits, event->source);
- }
-#endif
-
- /* Accumulate the event into the appropriate pool */
- pl = random_state.which;
- source = &random_state.pool[pl].source[event->source];
- randomdev_hash_iterate(&random_state.pool[pl].hash, event,
- sizeof(*event));
- source->bits += event->bits;
-
- /* Count the over-threshold sources in each pool */
- for (pl = 0; pl < 2; pl++) {
- overthreshhold[pl] = 0;
- for (src = RANDOM_START; src < ENTROPYSOURCE; src++) {
- if (random_state.pool[pl].source[src].bits
- > random_state.pool[pl].thresh)
- overthreshhold[pl]++;
- }
- }
-
- /* if any fast source over threshhold, reseed */
- if (overthreshhold[FAST])
- reseed(FAST);
+ int i, j;
+#ifdef _KERNEL
+ struct sysctl_oid *random_yarrow_o;
+#endif /* _KERNEL */
- /* if enough slow sources are over threshhold, reseed */
- if (overthreshhold[SLOW] >= random_state.slowoverthresh)
- reseed(SLOW);
+ memset(yarrow_state.start_cache.junk, 0, KEYSIZE);
+ randomdev_hash_init(&yarrow_state.start_cache.hash);
- /* Invert the fast/slow pool selector bit */
- random_state.which = !random_state.which;
-}
+ /* Set up the lock for the reseed/gate state */
+#ifdef _KERNEL
+ mtx_init(&random_reseed_mtx, "reseed mutex", NULL, MTX_DEF);
+#else /* !_KERNEL */
+ mtx_init(&random_reseed_mtx, mtx_plain);
+#endif /* _KERNEL */
-void
-random_yarrow_init_alg(struct sysctl_ctx_list *clist)
-{
- int i;
- struct sysctl_oid *random_yarrow_o;
+ /* Start unseeded, therefore blocked. */
+ yarrow_state.seeded = 0;
+#ifdef _KERNEL
/* Yarrow parameters. Do not adjust these unless you have
* have a very good clue about what they do!
*/
- random_yarrow_o = SYSCTL_ADD_NODE(clist,
+ random_yarrow_o = SYSCTL_ADD_NODE(&random_clist,
SYSCTL_STATIC_CHILDREN(_kern_random),
OID_AUTO, "yarrow", CTLFLAG_RW, 0,
"Yarrow Parameters");
- SYSCTL_ADD_PROC(clist,
+ SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
"gengateinterval", CTLTYPE_INT|CTLFLAG_RW,
- &random_state.gengateinterval, 10,
+ &yarrow_state.gengateinterval, 10,
random_check_uint_gengateinterval, "I",
"Generation gate interval");
- SYSCTL_ADD_PROC(clist,
+ SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
"bins", CTLTYPE_INT|CTLFLAG_RW,
- &random_state.bins, 10,
+ &yarrow_state.bins, 10,
random_check_uint_bins, "I",
"Execution time tuner");
- SYSCTL_ADD_PROC(clist,
+ SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
"fastthresh", CTLTYPE_INT|CTLFLAG_RW,
- &random_state.pool[0].thresh, (3*(BLOCKSIZE*8))/4,
+ &yarrow_state.pool[0].thresh, (3*(BLOCKSIZE*8))/4,
random_check_uint_fastthresh, "I",
"Fast reseed threshold");
- SYSCTL_ADD_PROC(clist,
+ SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
"slowthresh", CTLTYPE_INT|CTLFLAG_RW,
- &random_state.pool[1].thresh, (BLOCKSIZE*8),
+ &yarrow_state.pool[1].thresh, (BLOCKSIZE*8),
random_check_uint_slowthresh, "I",
"Slow reseed threshold");
- SYSCTL_ADD_PROC(clist,
+ SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
"slowoverthresh", CTLTYPE_INT|CTLFLAG_RW,
- &random_state.slowoverthresh, 2,
+ &yarrow_state.slowoverthresh, 2,
random_check_uint_slowoverthresh, "I",
"Slow over-threshold reseed");
+#endif /* _KERNEL */
- random_state.gengateinterval = 10;
- random_state.bins = 10;
- random_state.pool[0].thresh = (3*(BLOCKSIZE*8))/4;
- random_state.pool[1].thresh = (BLOCKSIZE*8);
- random_state.slowoverthresh = 2;
- random_state.which = FAST;
+ yarrow_state.gengateinterval = 10;
+ yarrow_state.bins = 10;
+ yarrow_state.pool[FAST].thresh = (3*(BLOCKSIZE*8))/4;
+ yarrow_state.pool[SLOW].thresh = (BLOCKSIZE*8);
+ yarrow_state.slowoverthresh = 2;
+
+ /* Ensure that the first time we read, we are gated. */
+ yarrow_state.outputblocks = yarrow_state.gengateinterval;
/* Initialise the fast and slow entropy pools */
- for (i = 0; i < 2; i++)
- randomdev_hash_init(&random_state.pool[i].hash);
+ for (i = FAST; i <= SLOW; i++) {
+ randomdev_hash_init(&yarrow_state.pool[i].hash);
+ for (j = RANDOM_START; j < ENTROPYSOURCE; j++)
+ yarrow_state.pool[i].source[j].bits = 0U;
+ }
/* Clear the counter */
- clear_counter();
-
- /* Set up a lock for the reseed process */
- mtx_init(&random_reseed_mtx, "Yarrow reseed", NULL, MTX_DEF);
+ uint128_clear(&yarrow_state.counter.whole);
}
void
random_yarrow_deinit_alg(void)
{
+
mtx_destroy(&random_reseed_mtx);
+ memset(&yarrow_state, 0, sizeof(yarrow_state));
+
+#ifdef _KERNEL
+ sysctl_ctx_free(&random_clist);
+#endif
+}
+
+static __inline void
+random_yarrow_post_insert(void)
+{
+ u_int pl, overthreshhold[2];
+ enum random_entropy_source src;
+
+#ifdef _KERNEL
+ mtx_assert(&random_reseed_mtx, MA_OWNED);
+#endif
+ /* Count the over-threshold sources in each pool */
+ for (pl = 0; pl < 2; pl++) {
+ overthreshhold[pl] = 0;
+ for (src = RANDOM_START; src < ENTROPYSOURCE; src++) {
+ if (yarrow_state.pool[pl].source[src].bits > yarrow_state.pool[pl].thresh)
+ overthreshhold[pl]++;
+ }
+ }
+
+ /* If enough slow sources are over threshhold, then slow reseed
+ * else if any fast source over threshhold, then fast reseed.
+ */
+ if (overthreshhold[SLOW] >= yarrow_state.slowoverthresh)
+ reseed(SLOW);
+ else if (overthreshhold[FAST] > 0 && yarrow_state.seeded)
+ reseed(FAST);
+}
+
+/* Process a single stochastic event off the harvest queue */
+void
+random_yarrow_process_event(struct harvest_event *event)
+{
+ u_int pl;
+
+ mtx_lock(&random_reseed_mtx);
+
+ /* Accumulate the event into the appropriate pool
+ * where each event carries the destination information.
+ * We lock against pool state modification which can happen
+ * during accumulation/reseeding and reading/regating
+ */
+ pl = event->he_destination % 2;
+ randomdev_hash_iterate(&yarrow_state.pool[pl].hash, event, sizeof(*event));
+ yarrow_state.pool[pl].source[event->he_source].bits += event->he_bits;
+
+ random_yarrow_post_insert();
+
+ mtx_unlock(&random_reseed_mtx);
+}
+
+/* Process a block of data suspected to be slightly stochastic */
+static void
+random_yarrow_process_buffer(uint8_t *buf, u_int length)
+{
+ static struct harvest_event event;
+ u_int i, pl;
+
+ /* Accumulate the data into the appropriate pools
+ * where each event carries the destination information.
+ * We lock against pool state modification which can happen
+ * during accumulation/reseeding and reading/regating
+ */
+ memset(event.he_entropy + sizeof(uint32_t), 0, HARVESTSIZE - sizeof(uint32_t));
+ for (i = 0; i < length/sizeof(uint32_t); i++) {
+ event.he_somecounter = get_cyclecount();
+ event.he_bits = 0; /* Fake */
+ event.he_source = RANDOM_CACHED;
+ event.he_destination = harvest_destination[RANDOM_CACHED]++;
+ event.he_size = sizeof(uint32_t);
+ *((uint32_t *)event.he_entropy) = *((uint32_t *)buf + i);
+
+ /* Do the actual entropy insertion */
+ pl = event.he_destination % 2;
+ randomdev_hash_iterate(&yarrow_state.pool[pl].hash, &event, sizeof(event));
+#ifdef DONT_DO_THIS_HERE
+ /* Don't do this here - do it in bulk at the end */
+ yarrow_state.pool[pl].source[RANDOM_CACHED].bits += bits;
+#endif
+ }
+ for (pl = FAST; pl <= SLOW; pl++)
+ yarrow_state.pool[pl].source[RANDOM_CACHED].bits += (length >> 4);
+
+ random_yarrow_post_insert();
}
static void
@@ -239,45 +323,60 @@ reseed(u_int fastslow)
* structures static.
*/
static uint8_t v[TIMEBIN][KEYSIZE]; /* v[i] */
+ static uint8_t hash[KEYSIZE]; /* h' */
+ static uint8_t temp[KEYSIZE];
static struct randomdev_hash context;
- uint8_t hash[KEYSIZE]; /* h' */
- uint8_t temp[KEYSIZE];
u_int i;
- enum esource j;
+ enum random_entropy_source j;
-#if 0
- printf("Yarrow: %s reseed\n", fastslow == FAST ? "fast" : "slow");
-#endif
+ KASSERT(yarrow_state.pool[FAST].thresh > 0, ("random: Yarrow fast threshold = 0"));
+ KASSERT(yarrow_state.pool[SLOW].thresh > 0, ("random: Yarrow slow threshold = 0"));
- /* The reseed task must not be jumped on */
- mtx_lock(&random_reseed_mtx);
+#ifdef RANDOM_DEBUG
+#ifdef RANDOM_DEBUG_VERBOSE
+ printf("random: %s %s\n", __func__, (fastslow == FAST ? "FAST" : "SLOW"));
+#endif
+ if (!yarrow_state.seeded) {
+ printf("random: %s - fast - thresh %d,1 - ", __func__, yarrow_state.pool[FAST].thresh);
+ for (i = RANDOM_START; i < ENTROPYSOURCE; i++)
+ printf(" %d", yarrow_state.pool[FAST].source[i].bits);
+ printf("\n");
+ printf("random: %s - slow - thresh %d,%d - ", __func__, yarrow_state.pool[SLOW].thresh, yarrow_state.slowoverthresh);
+ for (i = RANDOM_START; i < ENTROPYSOURCE; i++)
+ printf(" %d", yarrow_state.pool[SLOW].source[i].bits);
+ printf("\n");
+ }
+#endif
+#ifdef _KERNEL
+ mtx_assert(&random_reseed_mtx, MA_OWNED);
+#endif
/* 1. Hash the accumulated entropy into v[0] */
randomdev_hash_init(&context);
/* Feed the slow pool hash in if slow */
- if (fastslow == SLOW)
- randomdev_hash_iterate(&context,
- &random_state.pool[SLOW].hash,
- sizeof(struct randomdev_hash));
- randomdev_hash_iterate(&context,
- &random_state.pool[FAST].hash, sizeof(struct randomdev_hash));
+ if (fastslow == SLOW) {
+ randomdev_hash_finish(&yarrow_state.pool[SLOW].hash, temp);
+ randomdev_hash_iterate(&context, temp, sizeof(temp));
+ }
+ randomdev_hash_finish(&yarrow_state.pool[FAST].hash, temp);
+ randomdev_hash_iterate(&context, temp, sizeof(temp));
randomdev_hash_finish(&context, v[0]);
/* 2. Compute hash values for all v. _Supposed_ to be computationally
* intensive.
*/
- if (random_state.bins > TIMEBIN)
- random_state.bins = TIMEBIN;
- for (i = 1; i < random_state.bins; i++) {
+ if (yarrow_state.bins > TIMEBIN)
+ yarrow_state.bins = TIMEBIN;
+ for (i = 1; i < yarrow_state.bins; i++) {
randomdev_hash_init(&context);
/* v[i] #= h(v[i - 1]) */
randomdev_hash_iterate(&context, v[i - 1], KEYSIZE);
/* v[i] #= h(v[0]) */
randomdev_hash_iterate(&context, v[0], KEYSIZE);
/* v[i] #= h(i) */
- randomdev_hash_iterate(&context, &i, sizeof(u_int));
+ randomdev_hash_iterate(&context, &i, sizeof(i));
/* Return the hashval */
randomdev_hash_finish(&context, v[i]);
}
@@ -287,98 +386,107 @@ reseed(u_int fastslow)
*/
randomdev_hash_init(&context);
- randomdev_hash_iterate(&context, &random_state.key, KEYSIZE);
- for (i = 1; i < random_state.bins; i++)
- randomdev_hash_iterate(&context, &v[i], KEYSIZE);
+ randomdev_hash_iterate(&context, &yarrow_state.key, KEYSIZE);
+ for (i = 1; i < yarrow_state.bins; i++)
+ randomdev_hash_iterate(&context, v[i], KEYSIZE);
randomdev_hash_finish(&context, temp);
- randomdev_encrypt_init(&random_state.key, temp);
+ randomdev_encrypt_init(&yarrow_state.key, temp);
/* 4. Recompute the counter */
- clear_counter();
- randomdev_encrypt(&random_state.key, random_state.counter.byte, temp, BLOCKSIZE);
- memcpy(random_state.counter.byte, temp, BLOCKSIZE);
+ uint128_clear(&yarrow_state.counter.whole);
+ randomdev_encrypt(&yarrow_state.key, yarrow_state.counter.byte, temp, BLOCKSIZE);
+ memcpy(yarrow_state.counter.byte, temp, BLOCKSIZE);
/* 5. Reset entropy estimate accumulators to zero */
for (i = 0; i <= fastslow; i++)
for (j = RANDOM_START; j < ENTROPYSOURCE; j++)
- random_state.pool[i].source[j].bits = 0;
+ yarrow_state.pool[i].source[j].bits = 0;
/* 6. Wipe memory of intermediate values */
- memset((void *)v, 0, sizeof(v));
- memset((void *)temp, 0, sizeof(temp));
- memset((void *)hash, 0, sizeof(hash));
+ memset(v, 0, sizeof(v));
+ memset(temp, 0, sizeof(temp));
+ memset(hash, 0, sizeof(hash));
+ memset(&context, 0, sizeof(context));
+#ifdef RANDOM_RWFILE_WRITE_IS_OK /* Not defined so writes ain't gonna happen */
/* 7. Dump to seed file */
- /* XXX Not done here yet */
- /* Unblock the device if it was blocked due to being unseeded */
- randomdev_unblock();
+ /* This pseudo-code is documentation. Please leave it alone. */
+ seed_file = "<some file>";
+ error = randomdev_write_file(seed_file, <generated entropy>, PAGE_SIZE);
+ if (error == 0)
+ printf("random: entropy seed file '%s' successfully written\n", seed_file);
+#endif
- /* Release the reseed mutex */
- mtx_unlock(&random_reseed_mtx);
+ /* Unblock the device if it was blocked due to being unseeded */
+ if (!yarrow_state.seeded) {
+ yarrow_state.seeded = 1;
+ random_adaptor_unblock();
+ }
}
/* Internal function to return processed entropy from the PRNG */
-int
-random_yarrow_read(void *buf, int count)
+void
+random_yarrow_read(uint8_t *buf, u_int bytecount)
{
- static int cur = 0;
- static int gate = 1;
- static uint8_t genval[KEYSIZE];
- size_t tomove;
- int i;
- int retval;
+ u_int blockcount, i;
- /* Check for final read request */
- if (buf == NULL && count == 0)
- return (0);
+ /* Check for initial/final read requests */
+ if (buf == NULL)
+ return;
/* The reseed task must not be jumped on */
mtx_lock(&random_reseed_mtx);
- if (gate) {
- generator_gate();
- random_state.outputblocks = 0;
- gate = 0;
- }
- if (count > 0 && (size_t)count >= BLOCKSIZE) {
- retval = 0;
- for (i = 0; i < count; i += BLOCKSIZE) {
- increment_counter();
- randomdev_encrypt(&random_state.key, random_state.counter.byte, genval, BLOCKSIZE);
- tomove = MIN(count - i, BLOCKSIZE);
- memcpy((char *)buf + i, genval, tomove);
- if (++random_state.outputblocks >= random_state.gengateinterval) {
- generator_gate();
- random_state.outputblocks = 0;
- }
- retval += (int)tomove;
- cur = 0;
+ blockcount = (bytecount + BLOCKSIZE - 1)/BLOCKSIZE;
+ for (i = 0; i < blockcount; i++) {
+ if (yarrow_state.outputblocks++ >= yarrow_state.gengateinterval) {
+ generator_gate();
+ yarrow_state.outputblocks = 0;
}
+ uint128_increment(&yarrow_state.counter.whole);
+ randomdev_encrypt(&yarrow_state.key, yarrow_state.counter.byte, buf, BLOCKSIZE);
+ buf += BLOCKSIZE;
}
- else {
- if (!cur) {
- increment_counter();
- randomdev_encrypt(&random_state.key, random_state.counter.byte, genval, BLOCKSIZE);
- memcpy(buf, genval, (size_t)count);
- cur = BLOCKSIZE - count;
- if (++random_state.outputblocks >= random_state.gengateinterval) {
- generator_gate();
- random_state.outputblocks = 0;
- }
- retval = count;
- }
- else {
- retval = MIN(cur, count);
- memcpy(buf, &genval[BLOCKSIZE - cur], (size_t)retval);
- cur -= retval;
- }
+
+ mtx_unlock(&random_reseed_mtx);
+}
+
+/* Internal function to hand external entropy to the PRNG */
+void
+random_yarrow_write(uint8_t *buf, u_int count)
+{
+ uintmax_t timestamp;
+
+ /* We must be locked for all this as plenty of state gets messed with */
+ mtx_lock(&random_reseed_mtx);
+
+ timestamp = get_cyclecount();
+ randomdev_hash_iterate(&yarrow_state.start_cache.hash, &timestamp, sizeof(timestamp));
+ randomdev_hash_iterate(&yarrow_state.start_cache.hash, buf, count);
+ timestamp = get_cyclecount();
+ randomdev_hash_iterate(&yarrow_state.start_cache.hash, &timestamp, sizeof(timestamp));
+ randomdev_hash_finish(&yarrow_state.start_cache.hash, yarrow_state.start_cache.junk);
+ randomdev_hash_init(&yarrow_state.start_cache.hash);
+
+#ifdef RANDOM_DEBUG_VERBOSE
+ {
+ int i;
+
+ printf("random: %s - ", __func__);
+ for (i = 0; i < KEYSIZE; i++)
+ printf("%02X", yarrow_state.start_cache.junk[i]);
+ printf("\n");
}
+#endif
+
+ random_yarrow_process_buffer(yarrow_state.start_cache.junk, KEYSIZE);
+ memset(yarrow_state.start_cache.junk, 0, KEYSIZE);
+
mtx_unlock(&random_reseed_mtx);
- return (retval);
}
static void
@@ -388,29 +496,26 @@ generator_gate(void)
uint8_t temp[KEYSIZE];
for (i = 0; i < KEYSIZE; i += BLOCKSIZE) {
- increment_counter();
- randomdev_encrypt(&random_state.key, random_state.counter.byte, temp + i, BLOCKSIZE);
+ uint128_increment(&yarrow_state.counter.whole);
+ randomdev_encrypt(&yarrow_state.key, yarrow_state.counter.byte, temp + i, BLOCKSIZE);
}
- randomdev_encrypt_init(&random_state.key, temp);
- memset((void *)temp, 0, KEYSIZE);
+ randomdev_encrypt_init(&yarrow_state.key, temp);
+ memset(temp, 0, KEYSIZE);
}
-/* Helper routine to perform explicit reseeds */
void
random_yarrow_reseed(void)
{
-#ifdef RANDOM_DEBUG
- int i;
-
- printf("%s(): fast:", __func__);
- for (i = RANDOM_START; i < ENTROPYSOURCE; ++i)
- printf(" %d", random_state.pool[FAST].source[i].bits);
- printf("\n");
- printf("%s(): slow:", __func__);
- for (i = RANDOM_START; i < ENTROPYSOURCE; ++i)
- printf(" %d", random_state.pool[SLOW].source[i].bits);
- printf("\n");
-#endif
+
reseed(SLOW);
}
+
+int
+random_yarrow_seeded(void)
+{
+
+ return (yarrow_state.seeded);
+}
+
+#endif /* RANDOM_YARROW */
diff --git a/sys/dev/random/yarrow.h b/sys/dev/random/yarrow.h
index f32313e..9ba0b4e 100644
--- a/sys/dev/random/yarrow.h
+++ b/sys/dev/random/yarrow.h
@@ -29,9 +29,16 @@
#ifndef SYS_DEV_RANDOM_YARROW_H_INCLUDED
#define SYS_DEV_RANDOM_YARROW_H_INCLUDED
-void random_yarrow_init_alg(struct sysctl_ctx_list *);
+#ifdef _KERNEL
+typedef struct mtx mtx_t;
+#endif
+
+void random_yarrow_init_alg(void);
void random_yarrow_deinit_alg(void);
-int random_yarrow_read(void *, int);
+void random_yarrow_read(uint8_t *, u_int);
+void random_yarrow_write(uint8_t *, u_int);
void random_yarrow_reseed(void);
+int random_yarrow_seeded(void);
+void random_yarrow_process_event(struct harvest_event *event);
#endif
OpenPOWER on IntegriCloud