summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/glxsb/glxsb.c3
-rw-r--r--sys/dev/hifn/hifn7751.c3
-rwxr-xr-xsys/dev/random/build.sh28
-rw-r--r--sys/dev/random/dummy_rng.c111
-rw-r--r--sys/dev/random/fortuna.c582
-rw-r--r--sys/dev/random/fortuna.h25
-rw-r--r--sys/dev/random/hash.c18
-rw-r--r--sys/dev/random/hash.h14
-rw-r--r--sys/dev/random/ivy.c17
-rw-r--r--sys/dev/random/live_entropy_sources.c190
-rw-r--r--sys/dev/random/live_entropy_sources.h59
-rw-r--r--sys/dev/random/nehemiah.c23
-rw-r--r--sys/dev/random/random_adaptors.c483
-rw-r--r--sys/dev/random/random_adaptors.h74
-rw-r--r--sys/dev/random/random_harvestq.c411
-rw-r--r--sys/dev/random/random_harvestq.h50
-rw-r--r--sys/dev/random/randomdev.c420
-rw-r--r--sys/dev/random/randomdev.h86
-rw-r--r--sys/dev/random/randomdev_none.c (renamed from sys/dev/random/randomdev_soft.h)51
-rw-r--r--sys/dev/random/randomdev_soft.c165
-rw-r--r--sys/dev/random/uint128.h43
-rw-r--r--sys/dev/random/unit_test.c119
-rw-r--r--sys/dev/random/unit_test.h33
-rw-r--r--sys/dev/random/yarrow.c567
-rw-r--r--sys/dev/random/yarrow.h25
-rw-r--r--sys/dev/rndtest/rndtest.c13
-rw-r--r--sys/dev/safe/safe.c3
-rw-r--r--sys/dev/syscons/scmouse.c2
-rw-r--r--sys/dev/syscons/syscons.c2
-rw-r--r--sys/dev/ubsec/ubsec.c3
-rw-r--r--sys/dev/virtio/random/virtio_random.c2
-rw-r--r--sys/dev/vt/vt_core.c2
-rw-r--r--sys/dev/vt/vt_sysmouse.c2
33 files changed, 1452 insertions, 2177 deletions
diff --git a/sys/dev/glxsb/glxsb.c b/sys/dev/glxsb/glxsb.c
index 943ce7d..817113b 100644
--- a/sys/dev/glxsb/glxsb.c
+++ b/sys/dev/glxsb/glxsb.c
@@ -476,7 +476,8 @@ glxsb_rnd(void *v)
if (status & SB_RNS_TRNG_VALID) {
value = bus_read_4(sc->sc_sr, SB_RANDOM_NUM);
/* feed with one uint32 */
- random_harvest(&value, sizeof(value), 32/2, RANDOM_PURE_GLXSB);
+ /* MarkM: FIX!! Check that this does not swamp the harvester! */
+ random_harvest_queue(&value, sizeof(value), 32/2, RANDOM_PURE_GLXSB);
}
callout_reset(&sc->sc_rngco, sc->sc_rnghz, glxsb_rnd, sc);
diff --git a/sys/dev/hifn/hifn7751.c b/sys/dev/hifn/hifn7751.c
index 5b72482..ba510be 100644
--- a/sys/dev/hifn/hifn7751.c
+++ b/sys/dev/hifn/hifn7751.c
@@ -258,7 +258,8 @@ hifn_partname(struct hifn_softc *sc)
static void
default_harvest(struct rndtest_state *rsp, void *buf, u_int count)
{
- random_harvest(buf, count, count*NBBY/2, RANDOM_PURE_HIFN);
+ /* MarkM: FIX!! Check that this does not swamp the harvester! */
+ random_harvest_queue(buf, count, count*NBBY/2, RANDOM_PURE_HIFN);
}
static u_int
diff --git a/sys/dev/random/build.sh b/sys/dev/random/build.sh
index e573dc1..95800c1 100755
--- a/sys/dev/random/build.sh
+++ b/sys/dev/random/build.sh
@@ -1,3 +1,29 @@
+#!/bin/sh
+#-
+# Copyright (c) 2013-2015 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$
#
# Basic script to build crude unit tests.
@@ -11,6 +37,7 @@ cc -g -O0 -pthread -DRANDOM_DEBUG -DRANDOM_YARROW \
../../crypto/rijndael/rijndael-alg-fst.c \
../../crypto/sha2/sha2.c \
../../crypto/sha2/sha256c.c \
+ -lz \
-o yunit_test
cc -g -O0 -pthread -DRANDOM_DEBUG -DRANDOM_FORTUNA \
-I../.. -lstdthreads -Wall \
@@ -21,4 +48,5 @@ cc -g -O0 -pthread -DRANDOM_DEBUG -DRANDOM_FORTUNA \
../../crypto/rijndael/rijndael-alg-fst.c \
../../crypto/sha2/sha2.c \
../../crypto/sha2/sha256c.c \
+ -lz \
-o funit_test
diff --git a/sys/dev/random/dummy_rng.c b/sys/dev/random/dummy_rng.c
deleted file mode 100644
index e78f5a8..0000000
--- a/sys/dev/random/dummy_rng.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*-
- * 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
- * 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"
-
-#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/random.h>
-#include <sys/syslog.h>
-#include <sys/systm.h>
-
-#include <dev/random/randomdev.h>
-#include <dev/random/random_adaptors.h>
-
-static int
-dummy_random_zero(void)
-{
-
- return (0);
-}
-
-static void
-dummy_random(void)
-{
-}
-
-/* ARGSUSED */
-static void
-dummy_random_init(void)
-{
-
-#ifdef RANDOM_DEBUG
- printf("random: %s\n", __func__);
-#endif
-
- randomdev_init_reader(dummy_random_read_phony);
-}
-
-/* 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.
- */
-void
-dummy_random_read_phony(uint8_t *buf, u_int count)
-{
- /* If no entropy device is loaded, don't spam the console with warnings */
- u_long randval;
- size_t size, i;
-
- /* srandom() is called in kern/init_main.c:proc0_post() */
-
- /* 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);
- }
-}
-
-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
index 2bb31f4..00beaac 100644
--- a/sys/dev/random/fortuna.c
+++ b/sys/dev/random/fortuna.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2013-2014 Mark R V Murray
+ * Copyright (c) 2013-2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,25 +25,24 @@
*
*/
-/* This implementation of Fortuna is based on the descriptions found in
- * ISBN 0-471-22357-3 "Practical Cryptography" by Ferguson and Schneier
- * ("F&S").
- *
- * The above book is superseded by ISBN 978-0-470-47424-2 "Cryptography
- * Engineering" by Ferguson, Schneier and Kohno ("FS&K"). The code has
- * not yet fully caught up with FS&K.
+/*
+ * This implementation of Fortuna is based on the descriptions found in
+ * ISBN 978-0-470-47424-2 "Cryptography Engineering" by Ferguson, Schneier
+ * and Kohno ("FS&K").
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#ifdef _KERNEL
-#include "opt_random.h"
+#include <sys/limits.h>
+#ifdef _KERNEL
#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/mutex.h>
#include <sys/random.h>
#include <sys/sysctl.h>
@@ -56,13 +55,10 @@ __FBSDID("$FreeBSD$");
#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>
@@ -79,351 +75,405 @@ __FBSDID("$FreeBSD$");
#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
+/* Defined in FS&K */
+#define RANDOM_FORTUNA_NPOOLS 32 /* The number of accumulation pools */
+#define RANDOM_FORTUNA_DEFPOOLSIZE 64 /* The default pool size/length for a (re)seed */
+#define RANDOM_FORTUNA_MAX_READ (1 << 20) /* Max bytes in a single read */
-/* 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.
+/*
+ * The allowable range of RANDOM_FORTUNA_DEFPOOLSIZE. The default value is above.
+ * Making RANDOM_FORTUNA_DEFPOOLSIZE too large will mean a long time between reseeds,
+ * and too small may compromise initial security but get faster reseeds.
+ */
+#define RANDOM_FORTUNA_MINPOOLSIZE 16
+#define RANDOM_FORTUNA_MAXPOOLSIZE UINT_MAX
+CTASSERT(RANDOM_FORTUNA_MINPOOLSIZE <= RANDOM_FORTUNA_DEFPOOLSIZE);
+CTASSERT(RANDOM_FORTUNA_DEFPOOLSIZE <= RANDOM_FORTUNA_MAXPOOLSIZE);
+
+/* This algorithm (and code) presumes that RANDOM_KEYSIZE is twice as large as RANDOM_BLOCKSIZE */
+CTASSERT(RANDOM_BLOCKSIZE == sizeof(uint128_t));
+CTASSERT(RANDOM_KEYSIZE == 2*RANDOM_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;
-
+ struct fs_pool { /* P_i */
+ u_int fsp_length; /* Only the first one is used by Fortuna */
+ struct randomdev_hash fsp_hash;
+ } fs_pool[RANDOM_FORTUNA_NPOOLS];
+ u_int fs_reseedcount; /* ReseedCnt */
+ uint128_t fs_counter; /* C */
+ struct randomdev_key fs_key; /* K */
+ u_int fs_minpoolsize; /* Extras */
/* Extras for the OS */
-
#ifdef _KERNEL
/* For use when 'pacing' the reseeds */
- sbintime_t lasttime;
+ sbintime_t fs_lasttime;
#endif
+ /* Reseed lock */
+ mtx_t fs_mtx;
} fortuna_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(fs_minpoolsize, RANDOM_FORTUNA_MINPOOLSIZE, RANDOM_FORTUNA_MAXPOOLSIZE);
+#else
+static uint8_t zero_region[RANDOM_ZERO_BLOCKSIZE];
+#endif
-static struct fortuna_start_cache {
- uint8_t junk[PAGE_SIZE];
- size_t length;
- struct randomdev_hash hash;
-} fortuna_start_cache;
+static void random_fortuna_pre_read(void);
+static void random_fortuna_read(uint8_t *, u_int);
+static void random_fortuna_post_read(void);
+static void random_fortuna_write(uint8_t *, u_int);
+static void random_fortuna_reseed(void);
+static int random_fortuna_seeded(void);
+static void random_fortuna_process_event(struct harvest_event *);
#ifdef _KERNEL
-static struct sysctl_ctx_list random_clist;
-RANDOM_CHECK_UINT(minpoolsize, MINPOOLSIZE, MAXPOOLSIZE);
+/* Interface to Adaptors system */
+struct random_algorithm random_alg_context = {
+ .ra_ident = "Fortuna",
+ .ra_pre_read = random_fortuna_pre_read,
+ .ra_read = random_fortuna_read,
+ .ra_post_read = random_fortuna_post_read,
+ .ra_write = random_fortuna_write,
+ .ra_reseed = random_fortuna_reseed,
+ .ra_seeded = random_fortuna_seeded,
+ .ra_event_processor = random_fortuna_process_event,
+ .ra_poolcount = RANDOM_FORTUNA_NPOOLS,
+};
#endif
-void
-random_fortuna_init_alg(void)
+/* ARGSUSED */
+static void
+random_fortuna_init_alg(void *unused __unused)
{
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
+ RANDOM_RESEED_INIT_LOCK();
+ /*
+ * Fortuna parameters. Do not adjust these unless you have
* have a very good clue about what they do!
*/
+ fortuna_state.fs_minpoolsize = RANDOM_FORTUNA_DEFPOOLSIZE;
+#ifdef _KERNEL
+ fortuna_state.fs_lasttime = 0;
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;
+ "minpoolsize", CTLTYPE_UINT | CTLFLAG_RWTUN,
+ &fortuna_state.fs_minpoolsize, RANDOM_FORTUNA_DEFPOOLSIZE,
+ random_check_uint_fs_minpoolsize, "IU",
+ "Minimum pool size necessary to cause a reseed");
+ KASSERT(fortuna_state.fs_minpoolsize > 0, ("random: Fortuna threshold must be > 0 at startup"));
#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;
+ /*-
+ * FS&K - InitializePRNG()
+ * - P_i = \epsilon
+ * - ReseedCNT = 0
+ */
+ for (i = 0; i < RANDOM_FORTUNA_NPOOLS; i++) {
+ randomdev_hash_init(&fortuna_state.fs_pool[i].fsp_hash);
+ fortuna_state.fs_pool[i].fsp_length = 0;
}
-
- /* 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));
+ fortuna_state.fs_reseedcount = 0;
+ /*-
+ * FS&K - InitializeGenerator()
+ * - C = 0
+ * - K = 0
+ */
+ fortuna_state.fs_counter = UINT128_ZERO;
+ explicit_bzero(&fortuna_state.fs_key, sizeof(fortuna_state.fs_key));
}
+#ifdef _KERNEL
+SYSINIT(random_fortuna, SI_SUB_RANDOM, SI_ORDER_THIRD, random_fortuna_init_alg, NULL);
+#endif
-void
-random_fortuna_deinit_alg(void)
+/* ARGSUSED */
+static void
+random_fortuna_deinit_alg(void *unused __unused)
{
- mtx_destroy(&random_reseed_mtx);
- memset(&fortuna_state, 0, sizeof(fortuna_state));
+ RANDOM_RESEED_DEINIT_LOCK();
+ explicit_bzero(&fortuna_state, sizeof(fortuna_state));
+#ifdef _KERNEL
+ sysctl_ctx_free(&random_clist);
+#endif
}
+#ifdef _KERNEL
+SYSUNINIT(random_fortuna, SI_SUB_RANDOM, SI_ORDER_THIRD, random_fortuna_deinit_alg, NULL);
+#endif
-/* F&S - AddRandomEvent() */
-/* Process a single stochastic event off the harvest queue */
+/*-
+ * FS&K - 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
+ RANDOM_RESEED_LOCK();
+ /*-
+ * FS&K - P_i = P_i|<harvested stuff>
+ * Accumulate the event into the appropriate pool
+ * where each event carries the destination information.
+ *
+ * The hash_init() and hash_finish() calls are done in
+ * random_fortuna_pre_read().
+ *
+ * We must be locked against pool state modification which can happen
+ * during accumulation/reseeding and reading/regating.
+ */
+ pl = event->he_destination % RANDOM_FORTUNA_NPOOLS;
+ randomdev_hash_iterate(&fortuna_state.fs_pool[pl].fsp_hash, event, sizeof(*event));
+ /*-
+ * Don't wrap the length. Doing the the hard way so as not to wrap at MAXUINT.
+ * This is a "saturating" add.
+ * XXX: FIX!!: We don't actually need lengths for anything but fs_pool[0],
+ * but it's been useful debugging to see them all.
*/
- /* 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);
+ if (RANDOM_FORTUNA_MAXPOOLSIZE - fortuna_state.fs_pool[pl].fsp_length > event->he_size)
+ fortuna_state.fs_pool[pl].fsp_length += event->he_size;
+ else
+ fortuna_state.fs_pool[pl].fsp_length = RANDOM_FORTUNA_MAXPOOLSIZE;
+ explicit_bzero(event, sizeof(*event));
+ RANDOM_RESEED_UNLOCK();
+}
+
+/*-
+ * Process a block of data suspected to be slightly stochastic.
+ * Do this by breaking it up and inserting the pieces as if
+ * they were separate events.
+ */
+static void
+random_fortuna_process_buffer(uint32_t *buf, u_int wordcount)
+{
+ static struct harvest_event event;
+ static u_int destination = 0;
+ int i;
+
+ for (i = 0; i < wordcount; i += sizeof(event.he_entropy)/sizeof(event.he_entropy[0])) {
+ event.he_somecounter = (uint32_t)get_cyclecount();
+ event.he_size = sizeof(event.he_entropy);
+ event.he_bits = event.he_size/8;
+ event.he_source = RANDOM_CACHED;
+ event.he_destination = destination++; /* Harmless cheating */
+ memcpy(event.he_entropy, buf + i, sizeof(event.he_entropy));
+ random_fortuna_process_event(&event);
+ }
}
-/* F&S - Reseed() */
-/* Reseed Mutex is held */
+/*-
+ * FS&K - Reseed()
+ * This introduces new key material into the output generator.
+ * Additionaly it increments the output generator's counter
+ * variable C. When C > 0, the output generator is seeded and
+ * will deliver output.
+ * The entropy_data buffer passed is a very specific size; the
+ * product of RANDOM_FORTUNA_NPOOLS and RANDOM_KEYSIZE.
+ */
static void
-reseed(uint8_t *junk, u_int length)
+random_fortuna_reseed_internal(uint32_t *entropy_data, u_int blockcount)
{
struct randomdev_hash context;
- uint8_t hash[KEYSIZE];
+ uint8_t hash[RANDOM_KEYSIZE];
- KASSERT(fortuna_state.minpoolsize > 0, ("random: Fortuna threshold = 0"));
-#ifdef _KERNEL
- mtx_assert(&random_reseed_mtx, MA_OWNED);
-#endif
-
- /* FS&K - K = Hd(K|s) where Hd(m) is H(H(0^512|m)) */
+ RANDOM_RESEED_ASSERT_LOCK_OWNED();
+ /*-
+ * FS&K - K = Hd(K|s) where Hd(m) is H(H(0^512|m))
+ * - C = C + 1
+ */
randomdev_hash_init(&context);
- randomdev_hash_iterate(&context, zero_region, 512/8);
- randomdev_hash_iterate(&context, &fortuna_state.key, sizeof(fortuna_state.key));
- randomdev_hash_iterate(&context, junk, length);
+ randomdev_hash_iterate(&context, zero_region, RANDOM_ZERO_BLOCKSIZE);
+ randomdev_hash_iterate(&context, &fortuna_state.fs_key, sizeof(fortuna_state.fs_key));
+ randomdev_hash_iterate(&context, entropy_data, RANDOM_KEYSIZE*blockcount);
randomdev_hash_finish(&context, hash);
randomdev_hash_init(&context);
- randomdev_hash_iterate(&context, hash, KEYSIZE);
+ randomdev_hash_iterate(&context, hash, RANDOM_KEYSIZE);
randomdev_hash_finish(&context, hash);
- randomdev_encrypt_init(&fortuna_state.key, hash);
- 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();
- /* FS&K - C = C + 1 */
- uint128_increment(&fortuna_state.counter.whole);
+ randomdev_encrypt_init(&fortuna_state.fs_key, hash);
+ explicit_bzero(hash, sizeof(hash));
+ /* Unblock the device if this is the first time we are reseeding. */
+ if (uint128_is_zero(fortuna_state.fs_counter))
+ randomdev_unblock();
+ uint128_increment(&fortuna_state.fs_counter);
}
-/* F&S - GenerateBlocks() */
-/* Reseed Mutex is held, and buf points to a whole number of blocks. */
+/*-
+ * FS&K - GenerateBlocks()
+ * Generate a number of complete blocks of random output.
+ */
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);
+ RANDOM_RESEED_ASSERT_LOCK_OWNED();
+ for (i = 0; i < blockcount; i++) {
+ /*-
+ * FS&K - r = r|E(K,C)
+ * - C = C + 1
+ */
+ randomdev_encrypt(&fortuna_state.fs_key, &fortuna_state.fs_counter, buf, RANDOM_BLOCKSIZE);
+ buf += RANDOM_BLOCKSIZE;
+ uint128_increment(&fortuna_state.fs_counter);
}
}
-/* F&S - PseudoRandomData() */
-/* Reseed Mutex is held, and buf points to a whole number of blocks. */
+/*-
+ * FS&K - PseudoRandomData()
+ * This generates no more than 2^20 bytes of data, and cleans up its
+ * internal state when finished. It is assumed that a whole number of
+ * blocks are available for writing; any excess generated will be
+ * ignored.
+ */
static __inline void
random_fortuna_genrandom(uint8_t *buf, u_int bytecount)
{
- static uint8_t temp[BLOCKSIZE*(KEYSIZE/BLOCKSIZE)];
+ static uint8_t temp[RANDOM_BLOCKSIZE*(RANDOM_KEYS_PER_BLOCK)];
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;
+ RANDOM_RESEED_ASSERT_LOCK_OWNED();
+ /*-
+ * FS&K - assert(n < 2^20 (== 1 MB)
+ * - r = first-n-bytes(GenerateBlocks(ceil(n/16)))
+ * - K = GenerateBlocks(2)
+ */
+ KASSERT((bytecount <= RANDOM_FORTUNA_MAX_READ), ("invalid single read request to Fortuna of %d bytes", bytecount));
+ blockcount = (bytecount + RANDOM_BLOCKSIZE - 1)/RANDOM_BLOCKSIZE;
random_fortuna_genblocks(buf, blockcount);
- /* TODO: FIX! remove memcpy()! */
- if (bytecount % BLOCKSIZE > 0) {
- random_fortuna_genblocks(temp, 1);
- memcpy(buf + (blockcount * BLOCKSIZE), temp, bytecount % BLOCKSIZE);
- }
-
- /* F&S - K = GenerateBlocks(2) */
- random_fortuna_genblocks(temp, KEYSIZE/BLOCKSIZE);
- randomdev_encrypt_init(&fortuna_state.key, temp);
- memset(temp, 0, sizeof(temp));
+ random_fortuna_genblocks(temp, RANDOM_KEYS_PER_BLOCK);
+ randomdev_encrypt_init(&fortuna_state.fs_key, temp);
+ explicit_bzero(temp, sizeof(temp));
}
-/* F&S - RandomData() */
-/* Used to return processed entropy from the PRNG */
-/* The argument buf points to a whole number of blocks. */
+/*-
+ * FS&K - RandomData()
+ * Used to return processed entropy from the PRNG.
+ * There is a pre_read and a post_read required to be present
+ * (but they can be null functions) in order to allow specific
+ * actions at the begin or the end of a read. Fortuna does its
+ * reseeding in the _pre_read() part, and _post_read() is not
+ * used.
+ */
void
-random_fortuna_read(uint8_t *buf, u_int bytecount)
+random_fortuna_pre_read(void)
{
#ifdef _KERNEL
- sbintime_t thistime;
+ sbintime_t now;
#endif
struct randomdev_hash context;
- uint8_t s[NPOOLS*KEYSIZE], temp[KEYSIZE];
- int i;
- u_int seedlength;
+ uint32_t s[RANDOM_FORTUNA_NPOOLS*RANDOM_KEYSIZE_WORDS];
+ uint8_t temp[RANDOM_KEYSIZE];
+ u_int i;
- /* We must be locked for all this as plenty of state gets messed with */
- mtx_lock(&random_reseed_mtx);
+ KASSERT(fortuna_state.fs_minpoolsize > 0, ("random: Fortuna threshold must be > 0"));
+#ifdef _KERNEL
+ /* FS&K - Use 'getsbinuptime()' to prevent reseed-spamming. */
+ now = getsbinuptime();
+#endif
+ RANDOM_RESEED_LOCK();
- /* 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
+ if (fortuna_state.fs_pool[0].fsp_length >= fortuna_state.fs_minpoolsize
#ifdef _KERNEL
- /* F&S - Use 'getsbinuptime()' to prevent reseed-spamming. */
- && ((thistime = getsbinuptime()) - fortuna_state.lasttime > hz/10)
+ /* FS&K - Use 'getsbinuptime()' to prevent reseed-spamming. */
+ && (now - fortuna_state.fs_lasttime > hz/10)
#endif
- ) {
+ ) {
#ifdef _KERNEL
- fortuna_state.lasttime = thistime;
+ fortuna_state.fs_lasttime = now;
#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;
- }
+ /* FS&K - ReseedCNT = ReseedCNT + 1 */
+ fortuna_state.fs_reseedcount++;
+ /* s = \epsilon at start */
+ for (i = 0; i < RANDOM_FORTUNA_NPOOLS; i++) {
+ /* FS&K - if Divides(ReseedCnt, 2^i) ... */
+ if ((fortuna_state.fs_reseedcount % (1 << i)) == 0) {
+ /*-
+ * FS&K - temp = (P_i)
+ * - P_i = \epsilon
+ * - s = s|H(temp)
+ */
+ randomdev_hash_finish(&fortuna_state.fs_pool[i].fsp_hash, temp);
+ randomdev_hash_init(&fortuna_state.fs_pool[i].fsp_hash);
+ fortuna_state.fs_pool[i].fsp_length = 0;
+ randomdev_hash_init(&context);
+ randomdev_hash_iterate(&context, temp, RANDOM_KEYSIZE);
+ randomdev_hash_finish(&context, s + i*RANDOM_KEYSIZE_WORDS);
+ } 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));
- }
+ {
+ u_int j;
+
+ printf("random: reseedcount [%d]", fortuna_state.fs_reseedcount);
+ for (j = 0; j < RANDOM_FORTUNA_NPOOLS; j++)
+ printf(" %X", fortuna_state.fs_pool[j].fsp_length);
+ printf("\n");
}
+#endif
+ /* FS&K */
+ random_fortuna_reseed_internal(s, i < RANDOM_FORTUNA_NPOOLS ? i + 1 : RANDOM_FORTUNA_NPOOLS);
+ /* Clean up and secure */
+ explicit_bzero(s, sizeof(s));
+ explicit_bzero(temp, sizeof(temp));
+ explicit_bzero(&context, sizeof(context));
}
- /* if buf != NULL do a regular read. */
- else
- random_fortuna_genrandom(buf, bytecount);
-
- mtx_unlock(&random_reseed_mtx);
+ RANDOM_RESEED_UNLOCK();
}
-/* Internal function to hand external entropy to the PRNG */
+/*-
+ * Main read from Fortuna.
+ * The supplied buf MUST be a multiple (>=0) of RANDOM_BLOCKSIZE in size.
+ * Lots of code presumes this for efficiency, both here and in other
+ * routines. You are NOT allowed to break this!
+ */
void
-random_fortuna_write(uint8_t *buf, u_int count)
+random_fortuna_read(uint8_t *buf, u_int bytecount)
{
- 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);
+ RANDOM_RESEED_LOCK();
+ random_fortuna_genrandom(buf, bytecount);
+ RANDOM_RESEED_UNLOCK();
+}
- randomdev_hash_init(&fortuna_start_cache.hash);
+void
+random_fortuna_post_read(void)
+{
- reseed(fortuna_start_cache.junk, MIN(PAGE_SIZE, fortuna_start_cache.length));
- memset(fortuna_start_cache.junk, 0, sizeof(fortuna_start_cache.junk));
+ /* CWOT */
+}
- mtx_unlock(&random_reseed_mtx);
+/* Internal function to hand external entropy to the PRNG. */
+void
+random_fortuna_write(uint8_t *buf, u_int count)
+{
+ struct randomdev_hash hash;
+ uint32_t entropy_data[RANDOM_KEYSIZE_WORDS], timestamp;
+
+ /* Extra timing here is helpful to scrape scheduler timing entropy */
+ randomdev_hash_init(&hash);
+ timestamp = (uint32_t)get_cyclecount();
+ randomdev_hash_iterate(&hash, &timestamp, sizeof(timestamp));
+ randomdev_hash_iterate(&hash, buf, count);
+ timestamp = (uint32_t)get_cyclecount();
+ randomdev_hash_iterate(&hash, &timestamp, sizeof(timestamp));
+ randomdev_hash_finish(&hash, entropy_data);
+ explicit_bzero(&hash, sizeof(hash));
+ random_fortuna_process_buffer(entropy_data, sizeof(entropy_data)/sizeof(entropy_data[0]));
+ explicit_bzero(entropy_data, sizeof(entropy_data));
}
void
@@ -437,7 +487,5 @@ int
random_fortuna_seeded(void)
{
- return (!uint128_is_zero(fortuna_state.counter.whole));
+ return (!uint128_is_zero(fortuna_state.fs_counter));
}
-
-#endif /* RANDOM_FORTUNA */
diff --git a/sys/dev/random/fortuna.h b/sys/dev/random/fortuna.h
index 81fcac3..43aad04 100644
--- a/sys/dev/random/fortuna.h
+++ b/sys/dev/random/fortuna.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2013 Mark R V Murray
+ * Copyright (c) 2013-2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,18 +27,21 @@
*/
#ifndef SYS_DEV_RANDOM_FORTUNA_H_INCLUDED
-#define SYS_DEV_RANDOM_FORTUNA_H_INCLUDED
+#define SYS_DEV_RANDOM_FORTUNA_H_INCLUDED
#ifdef _KERNEL
typedef struct mtx mtx_t;
+#define RANDOM_RESEED_INIT_LOCK(x) mtx_init(&fortuna_state.fs_mtx, "reseed mutex", NULL, MTX_DEF)
+#define RANDOM_RESEED_DEINIT_LOCK(x) mtx_destroy(&fortuna_state.fs_mtx)
+#define RANDOM_RESEED_LOCK(x) mtx_lock(&fortuna_state.fs_mtx)
+#define RANDOM_RESEED_UNLOCK(x) mtx_unlock(&fortuna_state.fs_mtx)
+#define RANDOM_RESEED_ASSERT_LOCK_OWNED(x) mtx_assert(&fortuna_state.fs_mtx, MA_OWNED)
+#else
+#define RANDOM_RESEED_INIT_LOCK(x) mtx_init(&fortuna_state.fs_mtx, mtx_plain)
+#define RANDOM_RESEED_DEINIT_LOCK(x) mtx_destroy(&fortuna_state.fs_mtx)
+#define RANDOM_RESEED_LOCK(x) mtx_lock(&fortuna_state.fs_mtx)
+#define RANDOM_RESEED_UNLOCK(x) mtx_unlock(&fortuna_state.fs_mtx)
+#define RANDOM_RESEED_ASSERT_LOCK_OWNED(x)
#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
+#endif /* SYS_DEV_RANDOM_FORTUNA_H_INCLUDED */
diff --git a/sys/dev/random/hash.c b/sys/dev/random/hash.c
index 844e423..284057c 100644
--- a/sys/dev/random/hash.c
+++ b/sys/dev/random/hash.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2000-2013 Mark R V Murray
+ * Copyright (c) 2000-2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -47,8 +47,8 @@ __FBSDID("$FreeBSD$");
#include <dev/random/hash.h>
-/* This code presumes that KEYSIZE is twice as large as BLOCKSIZE */
-CTASSERT(KEYSIZE == 2*BLOCKSIZE);
+/* This code presumes that RANDOM_KEYSIZE is twice as large as RANDOM_BLOCKSIZE */
+CTASSERT(RANDOM_KEYSIZE == 2*RANDOM_BLOCKSIZE);
/* Initialise the hash */
void
@@ -67,7 +67,7 @@ randomdev_hash_iterate(struct randomdev_hash *context, const void *data, size_t
}
/* Conclude by returning the hash in the supplied <*buf> which must be
- * KEYSIZE bytes long.
+ * RANDOM_KEYSIZE bytes long.
*/
void
randomdev_hash_finish(struct randomdev_hash *context, void *buf)
@@ -77,20 +77,20 @@ randomdev_hash_finish(struct randomdev_hash *context, void *buf)
}
/* Initialise the encryption routine by setting up the key schedule
- * from the supplied <*data> which must be KEYSIZE bytes of binary
- * data. Use CBC mode for better avalanche.
+ * from the supplied <*data> which must be RANDOM_KEYSIZE bytes of binary
+ * data.
*/
void
randomdev_encrypt_init(struct randomdev_key *context, const void *data)
{
- rijndael_cipherInit(&context->cipher, MODE_CBC, NULL);
- rijndael_makeKey(&context->key, DIR_ENCRYPT, KEYSIZE*8, data);
+ rijndael_cipherInit(&context->cipher, MODE_ECB, NULL);
+ rijndael_makeKey(&context->key, DIR_ENCRYPT, RANDOM_KEYSIZE*8, data);
}
/* Encrypt the supplied data using the key schedule preset in the context.
* <length> bytes are encrypted from <*d_in> to <*d_out>. <length> must be
- * a multiple of BLOCKSIZE.
+ * a multiple of RANDOM_BLOCKSIZE.
*/
void
randomdev_encrypt(struct randomdev_key *context, const void *d_in, void *d_out, u_int length)
diff --git a/sys/dev/random/hash.h b/sys/dev/random/hash.h
index d49de3a..ef7a922 100644
--- a/sys/dev/random/hash.h
+++ b/sys/dev/random/hash.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2000-2013 Mark R V Murray
+ * Copyright (c) 2000-2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,10 +27,14 @@
*/
#ifndef SYS_DEV_RANDOM_HASH_H_INCLUDED
-#define SYS_DEV_RANDOM_HASH_H_INCLUDED
+#define SYS_DEV_RANDOM_HASH_H_INCLUDED
-#define KEYSIZE 32 /* (in bytes) == 256 bits */
-#define BLOCKSIZE 16 /* (in bytes) == 128 bits */
+#define RANDOM_KEYSIZE 32 /* (in bytes) == 256 bits */
+#define RANDOM_KEYSIZE_WORDS (RANDOM_KEYSIZE/sizeof(uint32_t))
+#define RANDOM_BLOCKSIZE 16 /* (in bytes) == 128 bits */
+#define RANDOM_BLOCKSIZE_WORDS (RANDOM_BLOCKSIZE/sizeof(uint32_t))
+#define RANDOM_KEYS_PER_BLOCK (RANDOM_KEYSIZE/RANDOM_BLOCKSIZE)
+#define RANDOM_ZERO_BLOCKSIZE 64 /* (in bytes) == 512 zero bits */
struct randomdev_hash { /* Big! Make static! */
SHA256_CTX sha;
@@ -47,4 +51,4 @@ void randomdev_hash_finish(struct randomdev_hash *, void *);
void randomdev_encrypt_init(struct randomdev_key *, const void *);
void randomdev_encrypt(struct randomdev_key *context, const void *, void *, u_int);
-#endif
+#endif /* SYS_DEV_RANDOM_HASH_H_INCLUDED */
diff --git a/sys/dev/random/ivy.c b/sys/dev/random/ivy.c
index 71a61f4..a7cd32f 100644
--- a/sys/dev/random/ivy.c
+++ b/sys/dev/random/ivy.c
@@ -46,18 +46,15 @@ __FBSDID("$FreeBSD$");
#include <machine/specialreg.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>
#define RETRY_COUNT 10
static u_int random_ivy_read(void *, u_int);
-static struct live_entropy_source random_ivy = {
- .les_ident = "Intel Secure Key RNG",
- .les_source = RANDOM_PURE_RDRAND,
- .les_read = random_ivy_read
+static struct random_source random_ivy = {
+ .rs_ident = "Intel Secure Key RNG",
+ .rs_source = RANDOM_PURE_RDRAND,
+ .rs_read = random_ivy_read
};
static inline int
@@ -108,14 +105,14 @@ rdrand_modevent(module_t mod, int type, void *unused)
switch (type) {
case MOD_LOAD:
if (cpu_feature2 & CPUID2_RDRAND) {
- live_entropy_source_register(&random_ivy);
- printf("random: live provider: \"%s\"\n", random_ivy.les_ident);
+ random_source_register(&random_ivy);
+ printf("random: fast provider: \"%s\"\n", random_ivy.rs_ident);
}
break;
case MOD_UNLOAD:
if (cpu_feature2 & CPUID2_RDRAND)
- live_entropy_source_deregister(&random_ivy);
+ random_source_deregister(&random_ivy);
break;
case MOD_SHUTDOWN:
diff --git a/sys/dev/random/live_entropy_sources.c b/sys/dev/random/live_entropy_sources.c
deleted file mode 100644
index 9899cb4..0000000
--- a/sys/dev/random/live_entropy_sources.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*-
- * 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
- * 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/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/sbuf.h>
-#include <sys/sx.h>
-#include <sys/sysctl.h>
-#include <sys/systm.h>
-#include <sys/unistd.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 "live_entropy_sources.h"
-
-/*
- * The les_lock protects the consistency of the "struct les_head les_sources"
- */
-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 live_entropy_source *rsource)
-{
- struct live_entropy_sources *lles;
-
- KASSERT(rsource != NULL, ("invalid input to %s", __func__));
-
- lles = malloc(sizeof(*lles), M_ENTROPY, M_WAITOK);
- lles->lles_rsource = rsource;
-
- sx_xlock(&les_lock);
- LIST_INSERT_HEAD(&les_sources, lles, lles_entries);
- sx_xunlock(&les_lock);
-}
-
-void
-live_entropy_source_deregister(struct live_entropy_source *rsource)
-{
- struct live_entropy_sources *lles = NULL;
-
- KASSERT(rsource != NULL, ("invalid input to %s", __func__));
-
- sx_xlock(&les_lock);
- LIST_FOREACH(lles, &les_sources, lles_entries)
- if (lles->lles_rsource == rsource) {
- LIST_REMOVE(lles, lles_entries);
- break;
- }
- sx_xunlock(&les_lock);
- if (lles != NULL)
- free(lles, M_ENTROPY);
-}
-
-static int
-live_entropy_source_handler(SYSCTL_HANDLER_ARGS)
-{
- struct live_entropy_sources *lles;
- struct sbuf sbuf;
- int error, count;
-
- sx_slock(&les_lock);
-
- sbuf_new_for_sysctl(&sbuf, NULL, 64, req);
-
- 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);
-}
-
-/*
- * Run through all "live" sources reading entropy for the given
- * number of rounds, which should be a multiple of the number
- * of entropy accumulation pools in use; 2 for Yarrow and 32
- * for Fortuna.
- *
- * BEWARE!!!
- * This function runs inside the RNG thread! Don't do anything silly!
- */
-/* 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(void)
-{
- static struct harvest_event event;
- struct live_entropy_sources *lles;
- int i, read_rate;
- u_int n;
-
- sx_slock(&les_lock);
-
- /*
- * Walk over all of live entropy sources, and feed their output
- * to the system-wide RNG.
- */
- 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 */
- harvest_process_event(&event);
- }
-
- }
-
- sx_sunlock(&les_lock);
-}
-
-void
-live_entropy_sources_init(void)
-{
-
- 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");
-}
-
-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
deleted file mode 100644
index 95e2e4b..0000000
--- a/sys/dev/random/live_entropy_sources.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*-
- * 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
- * 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_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) lles_entries; /* list of providers */
- struct live_entropy_source *lles_rsource; /* associated random adaptor */
-};
-
-extern struct mtx live_mtx;
-
-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 68949df..1de08fa 100644
--- a/sys/dev/random/nehemiah.c
+++ b/sys/dev/random/nehemiah.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2013 Mark R V Murray
+ * Copyright (c) 2013-2015 Mark R V Murray
* Copyright (c) 2013 David E. O'Brien <obrien@NUXI.org>
* All rights reserved.
*
@@ -44,24 +44,17 @@ __FBSDID("$FreeBSD$");
#include <machine/specialreg.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>
static void random_nehemiah_init(void);
static void random_nehemiah_deinit(void);
static u_int random_nehemiah_read(void *, u_int);
-static struct live_entropy_source random_nehemiah = {
- .les_ident = "VIA Nehemiah Padlock RNG",
- .les_source = RANDOM_PURE_NEHEMIAH,
- .les_read = random_nehemiah_read
+static struct random_source random_nehemiah = {
+ .rs_ident = "VIA Nehemiah Padlock RNG",
+ .rs_source = RANDOM_PURE_NEHEMIAH,
+ .rs_read = random_nehemiah_read
};
-/* 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)() ?
- */
static struct fpu_kern_ctx *fpu_ctx_save;
/* This H/W source never stores more than 8 bytes in one go */
@@ -131,8 +124,8 @@ nehemiah_modevent(module_t mod, int type, void *unused)
switch (type) {
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_source_register(&random_nehemiah);
+ printf("random: fast provider: \"%s\"\n", random_nehemiah.rs_ident);
random_nehemiah_init();
}
break;
@@ -140,7 +133,7 @@ nehemiah_modevent(module_t mod, int type, void *unused)
case MOD_UNLOAD:
if (via_feature_rng & VIA_HAS_RNG)
random_nehemiah_deinit();
- live_entropy_source_deregister(&random_nehemiah);
+ random_source_deregister(&random_nehemiah);
break;
case MOD_SHUTDOWN:
diff --git a/sys/dev/random/random_adaptors.c b/sys/dev/random/random_adaptors.c
deleted file mode 100644
index 5a67f50..0000000
--- a/sys/dev/random/random_adaptors.c
+++ /dev/null
@@ -1,483 +0,0 @@
-/*-
- * 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>
- * 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/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/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 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 */
-
-/* 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 */
-
-static struct selinfo rsel;
-
-/* 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)
-{
- char rngs[128], *token, *cp;
- struct random_adaptors *rra, *rrai;
- struct random_adaptor *random_adaptor_previous;
- int primax;
-
- /* We are going to be messing with random_adaptor.
- * Exclusive lock is mandatory.
- */
- sx_assert(&random_adaptors_lock, SA_XLOCKED);
-
- random_adaptor_previous = random_adaptor;
-
- random_adaptor = NULL;
- if (TUNABLE_STR_FETCH("kern.random.active_adaptor", rngs, sizeof(rngs))) {
- cp = rngs;
-
- /* 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) {
- randomdev_deinit_reader();
- (random_adaptor_previous->ra_deinit)();
- }
- (random_adaptor->ra_init)();
- }
-
- randomdev_init_reader(random_adaptor->ra_read);
-}
-
-
-/* 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;
-
- KASSERT(name != NULL && ra != NULL, ("invalid input to %s", __func__));
-
- rra = malloc(sizeof(*rra), M_ENTROPY, M_WAITOK);
- rra->rra_name = name;
- rra->rra_ra = ra;
-
- sx_xlock(&random_adaptors_lock);
- LIST_INSERT_HEAD(&random_adaptors_list, rra, rra_entries);
- random_adaptor_choose();
- KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
- sx_xunlock(&random_adaptors_lock);
-}
-
-void
-random_adaptor_deregister(const char *name)
-{
- struct random_adaptors *rra;
-
- KASSERT(name != NULL, ("invalid input to %s", __func__));
-
- sx_xlock(&random_adaptors_lock);
- KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
- 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);
-
- 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
-
- random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
-
- sx_slock(&random_adaptors_lock);
-
- KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
-
- /* 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() && error == 0) {
- if (flags & O_NONBLOCK) {
- error = EWOULDBLOCK;
- break;
- }
-
- /* Sleep instead of going into a spin-frenzy */
- error = sx_sleep(&random_adaptor, &random_adaptors_lock,
- PUSER | PCATCH, "randrd", hz/10);
- KASSERT(random_adaptor != NULL, ("No active random adaptor in %s",
- __func__));
-
- /* keep tapping away at the pre-read until we seed/unblock. */
- (random_adaptor->ra_read)(NULL, 0);
- }
-
- mtx_lock(&random_read_rate_mtx);
-
- /* 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 == 0) {
- nbytes = uio->uio_resid;
-
- /* The actual read */
- 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);
- }
-
- /* Let the entropy source do any post-read cleanup. */
- (random_adaptor->ra_read)(NULL, 1);
-
- if (nbytes != uio->uio_resid && (error == ERESTART ||
- error == EINTR) )
- error = 0; /* Return partial read, not error. */
-
- }
- sx_sunlock(&random_adaptors_lock);
-
- free(random_buf, M_ENTROPY);
-
- return (error);
-}
-
-int
-random_adaptor_read_rate(void)
-{
- int ret;
-
- 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);
-}
-
-/* ARGSUSED */
-int
-random_adaptor_write(struct cdev *dev __unused, struct uio *uio, int flags __unused)
-{
- int c, error = 0;
- void *random_buf;
- ssize_t nbytes;
-
-#ifdef RANDOM_DEBUG
- printf("random: %s %zd\n", __func__, uio->uio_resid);
-#endif
-
- random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
-
- sx_slock(&random_adaptors_lock);
-
- KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
-
- nbytes = uio->uio_resid;
- while (uio->uio_resid > 0 && error == 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 */
- error = sx_sleep(&random_adaptor, &random_adaptors_lock,
- PUSER | PCATCH, "randwr", hz/10);
- KASSERT(random_adaptor != NULL, ("No active random adaptor in %s",
- __func__));
- }
-
- sx_sunlock(&random_adaptors_lock);
-
- if (nbytes != uio->uio_resid && (error == ERESTART ||
- error == EINTR) )
- error = 0; /* Partial write, not error. */
-
- free(random_buf, M_ENTROPY);
-
- return (error);
-}
-
-/* ARGSUSED */
-int
-random_adaptor_poll(struct cdev *dev __unused, int events, struct thread *td __unused)
-{
-
-#ifdef RANDOM_DEBUG
- printf("random: %s\n", __func__);
-#endif
-
- sx_slock(&random_adaptors_lock);
-
- KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
-
- if (events & (POLLIN | POLLRDNORM)) {
- if (random_adaptor->ra_seeded())
- events &= (POLLIN | POLLRDNORM);
- else
- selrecord(td, &rsel);
- }
-
- 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 int
-random_sysctl_active_adaptor_handler(SYSCTL_HANDLER_ARGS)
-{
- struct random_adaptors *rra;
- struct sbuf sbuf;
- int error;
-
- sx_slock(&random_adaptors_lock);
- KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
-
- 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",
- "Random Number Generator adaptors");
-
- SYSCTL_PROC(_kern_random, OID_AUTO, active_adaptor,
- CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
- NULL, 0, random_sysctl_active_adaptor_handler, "A",
- "Active Random Number Generator Adaptor");
-
- 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();
-}
-
-void
-random_adaptors_deinit(void)
-{
-
-#ifdef RANDOM_DEBUG
- printf("random: %s\n", __func__);
-#endif
-
- live_entropy_sources_deinit();
-
- /* Don't do this! Panic will surely follow! */
- /* random_adaptor_deregister("dummy"); */
-
- mtx_destroy(&random_read_rate_mtx);
-
- sx_destroy(&random_adaptors_lock);
-}
-
-/*
- * Reseed the active adaptor shortly before starting init(8).
- */
-/* ARGSUSED */
-static void
-random_adaptors_seed(void *unused __unused)
-{
-
- sx_slock(&random_adaptors_lock);
- KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
-
- random_adaptor->ra_reseed();
- sx_sunlock(&random_adaptors_lock);
-
- arc4rand(NULL, 0, 1);
-}
-SYSINIT(random_seed, SI_SUB_KTHREAD_INIT, SI_ORDER_FIRST,
- random_adaptors_seed, NULL);
diff --git a/sys/dev/random/random_adaptors.h b/sys/dev/random/random_adaptors.h
deleted file mode 100644
index 08076ce..0000000
--- a/sys/dev/random/random_adaptors.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*-
- * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
- * 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_RANDOM_ADAPTORS_H_INCLUDED
-#define SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED
-
-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) rra_entries; /* list of providers */
- const char *rra_name; /* name of random adaptor */
- struct random_adaptor *rra_ra;
-};
-
-/* Dummy "always-block" pseudo-device */
-extern struct random_adaptor randomdev_dummy;
-
-void random_adaptors_init(void);
-void random_adaptors_deinit(void);
-
-void random_adaptor_register(const char *, struct random_adaptor *);
-void random_adaptor_deregister(const char *);
-
-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 *);
-
-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 df6a853..93c1ed5 100644
--- a/sys/dev/random/random_harvestq.c
+++ b/sys/dev/random/random_harvestq.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2000-2014 Mark R V Murray
+ * Copyright (c) 2000-2015 Mark R V Murray
* Copyright (c) 2013 Arthur Mesh
* Copyright (c) 2004 Robert N. M. Watson
* All rights reserved.
@@ -30,16 +30,17 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include "opt_random.h"
-
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/conf.h>
#include <sys/eventhandler.h>
+#include <sys/hash.h>
#include <sys/kernel.h>
#include <sys/kthread.h>
#include <sys/linker.h>
#include <sys/lock.h>
#include <sys/malloc.h>
+#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/random.h>
#include <sys/sbuf.h>
@@ -49,9 +50,9 @@ __FBSDID("$FreeBSD$");
#include <machine/cpu.h>
#include <dev/random/randomdev.h>
-#include <dev/random/random_adaptors.h>
#include <dev/random/random_harvestq.h>
-#include <dev/random/live_entropy_sources.h>
+
+static void random_kthread(void);
/* List for the dynamic sysctls */
static struct sysctl_ctx_list random_clist;
@@ -62,122 +63,111 @@ static struct sysctl_ctx_list random_clist;
* supplied junk. When used, they are transferred back to the
* 'empty' queue.
*/
-#define RANDOM_FIFO_MAX 1024
+#define RANDOM_RING_MAX 1024
+#define RANDOM_ACCUM_MAX 8
-/*
- * The harvest mutex protects the consistency of the entropy Fifos and
- * empty fifo and other associated structures.
- */
-static struct mtx harvest_mtx;
+/* 1 to let the kernel thread run, 0 to terminate */
+volatile int random_kthread_control;
/*
- * 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.
+ * Put all the harvest queue context stuff in one place.
+ * this make is a bit easier to lock and protect.
*/
-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 *);
-
-/* Allow the sysadmin to select the broad category of
- * entropy types to harvest.
- */
-static u_int harvest_source_mask = ((1U << RANDOM_ENVIRONMENTAL_END) - 1);
-
-/* 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;
+static struct harvest_context {
+ /* The harvest mutex protects the consistency of the entropy Fifos and
+ * empty fifo and other associated structures.
+ */
+ struct mtx hc_mtx;
+ /* Round-robin destination cache. */
+ u_int hc_destination[ENTROPYSOURCE];
+ /* The context of the kernel thread processing harvested entropy */
+ struct proc *hc_kthread_proc;
+ /* Allow the sysadmin to select the broad category of
+ * entropy types to harvest.
+ */
+ u_int hc_source_mask;
+ /*
+ * Lockless ring buffer holding entropy events
+ * If ring.in == ring.out,
+ * the buffer is empty.
+ * If ring.in != ring.out,
+ * the buffer contains harvested entropy.
+ * If (ring.in + 1) == ring.out (mod RANDOM_RING_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.
+ */
+ struct entropy_ring {
+ struct harvest_event ring[RANDOM_RING_MAX];
+ volatile u_int in;
+ volatile u_int out;
+ } hc_entropy_ring;
+ struct fast_entropy_accumulator {
+ volatile u_int pos;
+ uint32_t buf[8];
+ } hc_entropy_fast_accumulator;
+} harvest_context;
+
+static struct kproc_desc random_proc_kp = {
+ "rand_harvestq",
+ random_kthread,
+ &harvest_context.hc_kthread_proc,
+};
-/* <0 to end the kthread, 0 to let it run, 1 to flush the harvest queues */
-static int random_kthread_control = 0;
-static struct proc *random_kthread_proc;
+/* Pass the given event straight through to Fortuna/Yarrow/Whatever. */
+static __inline void
+random_harvestq_fast_process_event(struct harvest_event *event)
+{
+ if (random_alg_context.ra_event_processor)
+ random_alg_context.ra_event_processor(event);
+}
static void
-random_kthread(void *arg __unused)
+random_kthread(void)
{
- u_int maxloop, ring_out;
+ u_int maxloop, ring_out, i;
/*
- * 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,
+ * 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.
*/
- while (random_kthread_control >= 0) {
-
+ for (random_kthread_control = 1; random_kthread_control;) {
/* Deal with events, if any. Restrict the number we do in one go. */
- maxloop = RANDOM_FIFO_MAX;
- while (entropyfifo.ring_out != entropyfifo.ring_in) {
-
- 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;
-
- /* The ring may be filled quickly so don't loop forever. */
- if (--maxloop)
+ maxloop = RANDOM_RING_MAX;
+ while (harvest_context.hc_entropy_ring.out != harvest_context.hc_entropy_ring.in) {
+ ring_out = (harvest_context.hc_entropy_ring.out + 1)%RANDOM_RING_MAX;
+ random_harvestq_fast_process_event(harvest_context.hc_entropy_ring.ring + ring_out);
+ harvest_context.hc_entropy_ring.out = ring_out;
+ if (!--maxloop)
break;
-
}
-
- /*
- * Give the fast hardware sources a go
- */
- 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;
-
- /* 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));
-
+ random_sources_feed();
+ /* XXX: FIX!! This This seems a little slow; 8 items every 0.1s from UMA? */
+ for (i = 0; i < RANDOM_ACCUM_MAX; i++) {
+ if (harvest_context.hc_entropy_fast_accumulator.buf[i]) {
+ random_harvest_direct(harvest_context.hc_entropy_fast_accumulator.buf + i, sizeof(harvest_context.hc_entropy_fast_accumulator.buf[0]), 4, RANDOM_FAST);
+ harvest_context.hc_entropy_fast_accumulator.buf[i] = 0;
+ }
+ }
+ /* XXX: FIX!! This is a *great* place to pass hardware/live entropy to random(9) */
+ tsleep_sbt(&harvest_context.hc_kthread_proc, 0, "-", SBT_1S/10, 0, C_PREL(1));
}
-
- randomdev_set_wakeup_exit(&random_kthread_control);
+ wakeup(&harvest_context.hc_kthread_proc);
+ kproc_exit(0);
/* NOTREACHED */
}
-
-void
-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);
-}
+SYSINIT(random_device_h_proc, SI_SUB_CREATE_INIT, SI_ORDER_ANY, kproc_start, &random_proc_kp);
/* ARGSUSED */
-RANDOM_CHECK_UINT(harvestmask, 0, ((1U << RANDOM_ENVIRONMENTAL_END) - 1));
+RANDOM_CHECK_UINT(harvestmask, 0, RANDOM_HARVEST_EVERYTHING_MASK);
/* ARGSUSED */
static int
@@ -189,12 +179,11 @@ random_print_harvestmask(SYSCTL_HANDLER_ARGS)
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");
+ for (i = RANDOM_ENVIRONMENTAL_END; i >= 0; i--)
+ sbuf_cat(&sbuf, (harvest_context.hc_source_mask & (1 << i)) ? "1" : "0");
error = sbuf_finish(&sbuf);
sbuf_delete(&sbuf);
}
-
return (error);
}
@@ -208,8 +197,8 @@ static const char *(random_source_descr[]) = {
"NET_NG",
"INTERRUPT",
"SWI",
- "UMA_ALLOC",
- "", /* "ENVIRONMENTAL_END" */
+ "FS_ATIME",
+ "HIGH_PERFORMANCE", /* ENVIRONMENTAL_END */
"PURE_OCTEON",
"PURE_SAFE",
"PURE_GLXSB",
@@ -231,112 +220,111 @@ random_print_harvestmask_symbolic(SYSCTL_HANDLER_ARGS)
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] : "");
+ for (i = RANDOM_ENVIRONMENTAL_END; i >= 0; i--) {
+ sbuf_cat(&sbuf, (i == RANDOM_ENVIRONMENTAL_END) ? "" : ",");
+ sbuf_cat(&sbuf, !(harvest_context.hc_source_mask & (1 << i)) ? "[" : "");
+ sbuf_cat(&sbuf, random_source_descr[i]);
+ sbuf_cat(&sbuf, !(harvest_context.hc_source_mask & (1 << i)) ? "]" : "");
}
error = sbuf_finish(&sbuf);
sbuf_delete(&sbuf);
}
-
return (error);
}
-void
-random_harvestq_init(void (*event_processor)(struct harvest_event *), int poolcount)
+/* ARGSUSED */
+static void
+random_harvestq_init(void *unused __unused)
{
- 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
-
+ if (bootverbose)
+ printf("random: %s\n", __func__);
random_sys_o = SYSCTL_ADD_NODE(&random_clist,
SYSCTL_STATIC_CHILDREN(_kern_random),
OID_AUTO, "harvest", CTLFLAG_RW, 0,
"Entropy Device Parameters");
-
+ harvest_context.hc_source_mask = RANDOM_HARVEST_EVERYTHING_MASK;
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),
+ &harvest_context.hc_source_mask, 0,
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)");
+ RANDOM_HARVEST_INIT_LOCK();
+ harvest_context.hc_entropy_ring.in = harvest_context.hc_entropy_ring.out = 0;
+}
+SYSINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_SECOND, random_harvestq_init, NULL);
- /* 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, NULL,
- &random_kthread_proc, RFHIGHPID, 0, "rand_harvestq");
-
- if (error != 0)
- panic("Cannot create entropy maintenance thread.");
+/*
+ * This is used to prime the RNG by grabbing any early random stuff
+ * known to the kernel, and inserting it directly into the hashing
+ * module, e.g. Fortuna or Yarrow.
+ */
+/* ARGSUSED */
+static void
+random_harvestq_prime(void *unused __unused)
+{
+ struct harvest_event event;
+ size_t count, size, i;
+ uint8_t *keyfile, *data;
- /* Get entropy that may have been preloaded by loader(8)
+ /*
+ * 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");
+ keyfile = preload_search_by_type(RANDOM_HARVESTQ_BOOT_ENTROPY_FILE);
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");
+ for (i = 0; i < size; i += sizeof(event.he_entropy)) {
+ count = sizeof(event.he_entropy);
+ event.he_somecounter = (uint32_t)get_cyclecount();
+ event.he_size = count;
+ event.he_bits = count/4; /* Underestimate the size for Yarrow */
+ event.he_source = RANDOM_CACHED;
+ event.he_destination = harvest_context.hc_destination[0]++;
+ memcpy(event.he_entropy, data + i, sizeof(event.he_entropy));
+ random_harvestq_fast_process_event(&event);
+ explicit_bzero(&event, sizeof(event));
+ }
+ explicit_bzero(data, size);
+ if (bootverbose)
+ printf("random: read %zu bytes from preloaded cache\n", size);
+ } else
+ if (bootverbose)
+ printf("random: no preloaded entropy cache\n");
}
-
}
+SYSINIT(random_device_prime, SI_SUB_RANDOM, SI_ORDER_FOURTH, random_harvestq_prime, NULL);
-void
-random_harvestq_deinit(void)
+/* ARGSUSED */
+static void
+random_harvestq_deinit(void *unused __unused)
{
-#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);
-
+ /* Command the hash/reseed thread to end and wait for it to finish */
+ random_kthread_control = 0;
+ tsleep(&harvest_context.hc_kthread_proc, 0, "term", 0);
sysctl_ctx_free(&random_clist);
}
+SYSUNINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_SECOND, random_harvestq_deinit, NULL);
-/*
- * Entropy harvesting routine.
- * This is supposed to be fast; do not do anything slow in here!
+/*-
+ * Entropy harvesting queue routine.
*
+ * This is supposed to be fast; do not do anything slow in here!
* It is also illegal (and morally reprehensible) to insert any
- * high-rate data here. "High-rate" is define as a data source
+ * high-rate data here. "High-rate" is defined as a data source
* that will usually cause lots of failures of the "Lockless read"
* check a few lines below. This includes the "always-on" sources
* like the Intel "rdrand" or the VIA Nehamiah "xstore" sources.
@@ -346,37 +334,78 @@ random_harvestq_deinit(void)
* read which can be quite expensive.
*/
void
-random_harvestq_internal(const void *entropy, u_int count, u_int bits,
- enum random_entropy_source origin)
+random_harvest_queue(const void *entropy, u_int count, u_int bits, enum random_entropy_source origin)
{
struct harvest_event *event;
u_int ring_in;
- KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE,
- ("random_harvest_internal: origin %d invalid\n", origin));
-
- /* Mask out unwanted sources */
- if (!(harvest_source_mask & (1U << origin)))
+ KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, ("%s: origin %d invalid\n", __func__, origin));
+ if (!(harvest_context.hc_source_mask & (1 << origin)))
return;
-
- /* Lock ring_in against multi-thread contention */
- mtx_lock_spin(&harvest_mtx);
- ring_in = (entropyfifo.ring_in + 1)%RANDOM_FIFO_MAX;
- if (ring_in != entropyfifo.ring_out) {
+ RANDOM_HARVEST_LOCK();
+ ring_in = (harvest_context.hc_entropy_ring.in + 1)%RANDOM_RING_MAX;
+ if (ring_in != harvest_context.hc_entropy_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 = harvest_context.hc_entropy_ring.ring + ring_in;
+ event->he_somecounter = (uint32_t)get_cyclecount();
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;
+ event->he_destination = harvest_context.hc_destination[origin]++;
+ event->he_bits = bits;
+ if (count <= sizeof(event->he_entropy)) {
+ event->he_size = count;
+ memcpy(event->he_entropy, entropy, count);
+ }
+ else {
+ /* Big event, so squash it */
+ event->he_size = sizeof(event->he_entropy[0]);
+ event->he_entropy[0] = jenkins_hash(entropy, count, (uint32_t)(uintptr_t)event);
+ }
+ harvest_context.hc_entropy_ring.in = ring_in;
}
- mtx_unlock_spin(&harvest_mtx);
+ RANDOM_HARVEST_UNLOCK();
+}
+
+/*-
+ * Entropy harvesting fast routine.
+ *
+ * This is supposed to be very fast; do not do anything slow in here!
+ * This is the right place for high-rate harvested data.
+ */
+void
+random_harvest_fast(const void *entropy, u_int count, u_int bits, enum random_entropy_source origin)
+{
+ u_int pos;
+
+ KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, ("%s: origin %d invalid\n", __func__, origin));
+ /* XXX: FIX!! The above KASSERT is BS. Right now we ignore most structure and just accumulate the supplied data */
+ if (!(harvest_context.hc_source_mask & (1 << origin)))
+ return;
+ pos = harvest_context.hc_entropy_fast_accumulator.pos;
+ harvest_context.hc_entropy_fast_accumulator.buf[pos] ^= jenkins_hash(entropy, count, (uint32_t)get_cyclecount());
+ harvest_context.hc_entropy_fast_accumulator.pos = (pos + 1)%RANDOM_ACCUM_MAX;
+}
+
+/*-
+ * Entropy harvesting direct routine.
+ *
+ * This is not supposed to be fast, but will only be used during
+ * (e.g.) booting when initial entropy is being gathered.
+ */
+void
+random_harvest_direct(const void *entropy, u_int count, u_int bits, enum random_entropy_source origin)
+{
+ struct harvest_event event;
+
+ KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, ("%s: origin %d invalid\n", __func__, origin));
+ if (!(harvest_context.hc_source_mask & (1 << origin)))
+ return;
+ count = MIN(count, sizeof(event.he_entropy));
+ event.he_somecounter = (uint32_t)get_cyclecount();
+ event.he_size = count;
+ event.he_bits = bits;
+ event.he_source = origin;
+ event.he_destination = harvest_context.hc_destination[origin]++;
+ memcpy(event.he_entropy, entropy, count);
+ random_harvestq_fast_process_event(&event);
+ explicit_bzero(&event, sizeof(event));
}
diff --git a/sys/dev/random/random_harvestq.h b/sys/dev/random/random_harvestq.h
index ab09a3f..f1de86f 100644
--- a/sys/dev/random/random_harvestq.h
+++ b/sys/dev/random/random_harvestq.h
@@ -1,6 +1,5 @@
/*-
- * Copyright (c) 2013-2014 Mark R V Murray
- * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
+ * Copyright (c) 2013-2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,43 +27,26 @@
*/
#ifndef SYS_DEV_RANDOM_RANDOM_HARVESTQ_H_INCLUDED
-#define SYS_DEV_RANDOM_RANDOM_HARVESTQ_H_INCLUDED
+#define SYS_DEV_RANDOM_RANDOM_HARVESTQ_H_INCLUDED
-#define HARVESTSIZE 16 /* max size of each harvested entropy unit */
+#define HARVESTSIZE 2 /* Max length in words of each harvested entropy unit */
/* 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(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 *);
-
-/* Round-robin destination cache. */
-extern u_int harvest_destination[ENTROPYSOURCE];
+ uint32_t he_somecounter; /* fast counter for clock jitter */
+ uint32_t he_entropy[HARVESTSIZE];/* some harvested entropy */
+ uint8_t he_size; /* harvested entropy byte count */
+ uint8_t he_bits; /* stats about the entropy */
+ uint8_t he_destination; /* destination pool of this entropy */
+ uint8_t he_source; /* origin of the entropy */
+} __packed;
+
+#define RANDOM_HARVESTQ_BOOT_ENTROPY_FILE "/boot/entropy"
+
+#define RANDOM_HARVEST_INIT_LOCK(x) mtx_init(&harvest_context.hc_mtx, "entropy harvest mutex", NULL, MTX_SPIN)
+#define RANDOM_HARVEST_LOCK(x) mtx_lock_spin(&harvest_context.hc_mtx)
+#define RANDOM_HARVEST_UNLOCK(x) mtx_unlock_spin(&harvest_context.hc_mtx)
#endif /* SYS_DEV_RANDOM_RANDOM_HARVESTQ_H_INCLUDED */
diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c
index 9d41aed..1d9dcbe 100644
--- a/sys/dev/random/randomdev.c
+++ b/sys/dev/random/randomdev.c
@@ -1,6 +1,5 @@
/*-
- * Copyright (c) 2000-2013 Mark R V Murray
- * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
+ * Copyright (c) 2000-2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,28 +25,9 @@
*
*/
-/*
- * 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>
@@ -59,27 +39,42 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/module.h>
#include <sys/malloc.h>
+#include <sys/poll.h>
#include <sys/proc.h>
#include <sys/random.h>
+#include <sys/sbuf.h>
+#include <sys/selinfo.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
#include <sys/uio.h>
#include <sys/unistd.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>
-#define RANDOM_MINOR 0
+#include "opt_random.h"
+
+#if defined(RANDOM_DUMMY) && defined(RANDOM_YARROW)
+#error "Cannot define both RANDOM_DUMMY and RANDOM_YARROW"
+#endif
+#define RANDOM_MINOR 0
+
+static d_read_t randomdev_read;
+static d_write_t randomdev_write;
+static d_poll_t randomdev_poll;
static d_ioctl_t randomdev_ioctl;
static struct cdevsw random_cdevsw = {
.d_name = "random",
.d_version = D_VERSION,
- .d_read = random_adaptor_read,
- .d_write = random_adaptor_write,
- .d_poll = random_adaptor_poll,
+ .d_read = randomdev_read,
+ .d_write = randomdev_write,
+ .d_poll = randomdev_poll,
.d_ioctl = randomdev_ioctl,
};
@@ -87,163 +82,326 @@ static struct cdevsw random_cdevsw = {
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");
+SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Cryptographically Secure Random Number Generator");
MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures");
-/* ARGSUSED */
-static int
-randomdev_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused,
- int flags __unused, struct thread *td __unused)
-{
- int error = 0;
-
- switch (cmd) {
- /* Really handled in upper layer */
- case FIOASYNC:
- case FIONBIO:
- break;
+#if defined(RANDOM_DUMMY)
- default:
- error = ENOTTY;
+/*-
+ * Dummy "always block" pseudo algorithm, used when there is no real
+ * random(4) driver to provide a CSPRNG.
+ */
- }
+static u_int
+dummy_random_zero(void)
+{
- return (error);
+ return (0);
}
-/* 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)
+static void
+dummy_random(void)
{
-
- wakeup(control);
- kproc_exit(0);
- /* NOTREACHED */
}
-/* ARGSUSED */
-static int
-randomdev_modevent(module_t mod __unused, int type, void *data __unused)
-{
- int error = 0;
+struct random_algorithm random_alg_context = {
+ .ra_ident = "Dummy",
+ .ra_reseed = dummy_random,
+ .ra_seeded = (random_alg_seeded_t *)dummy_random_zero,
+ .ra_pre_read = dummy_random,
+ .ra_read = (random_alg_read_t *)dummy_random_zero,
+ .ra_post_read = dummy_random,
+ .ra_write = (random_alg_write_t *)dummy_random_zero,
+ .ra_event_processor = NULL,
+ .ra_poolcount = 0,
+};
- 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;
+#else /* !defined(RANDOM_DUMMY) */
- case MOD_UNLOAD:
- random_adaptors_deinit();
- destroy_dev(random_dev);
- break;
+LIST_HEAD(sources_head, random_sources);
+static struct sources_head source_list = LIST_HEAD_INITIALIZER(source_list);
+static u_int read_rate;
- case MOD_SHUTDOWN:
- break;
+#endif /* defined(RANDOM_DUMMY) */
- default:
- error = EOPNOTSUPP;
- break;
+static struct selinfo rsel;
+/*
+ * This is the read uio(9) interface for random(4).
+ */
+/* ARGSUSED */
+static int
+randomdev_read(struct cdev *dev __unused, struct uio *uio, int flags)
+{
+ uint8_t *random_buf;
+ int c, error;
+ ssize_t nbytes;
+
+ random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
+ random_alg_context.ra_pre_read();
+ /* (Un)Blocking logic */
+ error = 0;
+ while (!random_alg_context.ra_seeded() && error == 0) {
+ if (flags & O_NONBLOCK) {
+ error = EWOULDBLOCK;
+ break;
+ }
+ tsleep(&random_alg_context, 0, "randrd", hz/10);
+ /* keep tapping away at the pre-read until we seed/unblock. */
+ random_alg_context.ra_pre_read();
+ printf("random: %s unblock (error = %d)\n", __func__, error);
}
-
+ if (error == 0) {
+#if !defined(RANDOM_DUMMY)
+ /* XXX: FIX!! Next line as an atomic operation? */
+ read_rate += (uio->uio_resid + sizeof(uint32_t))/sizeof(uint32_t);
+#endif
+ nbytes = uio->uio_resid;
+ while (uio->uio_resid && !error) {
+ c = MIN(uio->uio_resid, PAGE_SIZE);
+ random_alg_context.ra_read(random_buf, c);
+ error = uiomove(random_buf, c, uio);
+ }
+ random_alg_context.ra_post_read();
+ if (nbytes != uio->uio_resid && (error == ERESTART || error == EINTR) )
+ /* Return partial read, not error. */
+ error = 0;
+ }
+ free(random_buf, M_ENTROPY);
return (error);
}
-DEV_MODULE_ORDERED(randomdev, randomdev_modevent, NULL, SI_ORDER_SECOND);
-MODULE_VERSION(randomdev, 1);
-
-/* ================
- * Harvesting stubs
- * ================
+/*-
+ * Kernel API version of read_random().
+ * This is similar to random_alg_read(),
+ * except it doesn't interface with uio(9).
+ * It cannot assumed that random_buf is a multiple of
+ * RANDOM_BLOCKSIZE bytes.
*/
+u_int
+read_random(void *random_buf, u_int len)
+{
+ u_int read_len, total_read, c;
+ uint8_t local_buf[len + RANDOM_BLOCKSIZE];
+
+ KASSERT(random_buf != NULL, ("No suitable random buffer in %s", __func__));
+ random_alg_context.ra_pre_read();
+ /* (Un)Blocking logic; if not seeded, return nothing. */
+ if (random_alg_context.ra_seeded()) {
+#if !defined(RANDOM_DUMMY)
+ /* XXX: FIX!! Next line as an atomic operation? */
+ read_rate += (len + sizeof(uint32_t))/sizeof(uint32_t);
+#endif
+ read_len = len;
+ total_read = 0;
+ while (read_len) {
+ c = MIN(read_len, PAGE_SIZE);
+ random_alg_context.ra_read(&local_buf[total_read], c);
+ read_len -= c;
+ total_read += c;
+ }
+ memcpy(random_buf, local_buf, len);
+ } else
+ len = 0;
+ random_alg_context.ra_post_read();
+ return (len);
+}
-/* 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_harvest_phony(const void *entropy __unused, u_int count __unused,
- u_int bits __unused, enum random_entropy_source origin __unused)
+static int
+randomdev_write(struct cdev *dev __unused, struct uio *uio, int flags __unused)
{
+ uint8_t *random_buf;
+ int c, error = 0;
+ ssize_t nbytes;
+
+ random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
+ nbytes = uio->uio_resid;
+ while (uio->uio_resid > 0 && error == 0) {
+ c = MIN(uio->uio_resid, PAGE_SIZE);
+ error = uiomove(random_buf, c, uio);
+ if (error)
+ break;
+ random_alg_context.ra_write(random_buf, c);
+ tsleep(&random_alg_context, 0, "randwr", hz/10);
+ }
+ if (nbytes != uio->uio_resid && (error == ERESTART || error == EINTR))
+ /* Partial write, not error. */
+ error = 0;
+ free(random_buf, M_ENTROPY);
+ return (error);
}
-/* 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;
+/* ARGSUSED */
+static int
+randomdev_poll(struct cdev *dev __unused, int events, struct thread *td __unused)
+{
-/* Initialise the harvester when/if it is loaded */
+ if (events & (POLLIN | POLLRDNORM)) {
+ if (random_alg_context.ra_seeded())
+ events &= (POLLIN | POLLRDNORM);
+ else
+ selrecord(td, &rsel);
+ }
+ return (events);
+}
+
+/* This will be called by the entropy processor when it seeds itself and becomes secure */
void
-randomdev_init_harvester(void (*reaper)(const void *, u_int, u_int, enum random_entropy_source))
+randomdev_unblock(void)
{
- reap_func = reaper;
+ selwakeuppri(&rsel, PUSER);
+ wakeup(&random_alg_context);
+ printf("random: unblocking device.\n");
+ /* Do random(9) a favour while we are about it. */
+ (void)atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_NONE, ARC4_ENTR_HAVE);
}
-/* Deinitialise the harvester when/if it is unloaded */
-void
-randomdev_deinit_harvester(void)
+/* ARGSUSED */
+static int
+randomdev_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused,
+ int flags __unused, struct thread *td __unused)
{
+ int error = 0;
+
+ switch (cmd) {
+ /* Really handled in upper layer */
+ case FIOASYNC:
+ case FIONBIO:
+ break;
+ default:
+ error = ENOTTY;
+ }
- reap_func = random_harvest_phony;
+ return (error);
}
-/* 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)
+random_source_register(struct random_source *rsource)
{
+#if defined(RANDOM_DUMMY)
+ (void)rsource;
+#else /* !defined(RANDOM_DUMMY) */
+ struct random_sources *rrs;
- (*reap_func)(entropy, count, bits, origin);
-}
+ KASSERT(rsource != NULL, ("invalid input to %s", __func__));
-/* ================================
- * Internal reading stubs and fakes
- * ================================
- */
+ rrs = malloc(sizeof(*rrs), M_ENTROPY, M_WAITOK);
+ rrs->rrs_source = rsource;
-/* Hold the address of the routine which is actually called */
-static void (*read_func)(uint8_t *, u_int) = dummy_random_read_phony;
+ printf("random: registering fast source %s\n", rsource->rs_ident);
+ LIST_INSERT_HEAD(&source_list, rrs, rrs_entries);
+#endif /* defined(RANDOM_DUMMY) */
+}
-/* Initialise the reader when/if it is loaded */
void
-randomdev_init_reader(void (*reader)(uint8_t *, u_int))
+random_source_deregister(struct random_source *rsource)
{
-
- read_func = reader;
+#if defined(RANDOM_DUMMY)
+ (void)rsource;
+#else /* !defined(RANDOM_DUMMY) */
+ struct random_sources *rrs = NULL;
+
+ KASSERT(rsource != NULL, ("invalid input to %s", __func__));
+ LIST_FOREACH(rrs, &source_list, rrs_entries)
+ if (rrs->rrs_source == rsource) {
+ LIST_REMOVE(rrs, rrs_entries);
+ break;
+ }
+ if (rrs != NULL)
+ free(rrs, M_ENTROPY);
+#endif /* defined(RANDOM_DUMMY) */
}
-/* Deinitialise the reader when/if it is unloaded */
+#if !defined(RANDOM_DUMMY)
+/*
+ * Run through all fast sources reading entropy for the given
+ * number of rounds, which should be a multiple of the number
+ * of entropy accumulation pools in use; 2 for Yarrow and 32
+ * for Fortuna.
+ *
+ * BEWARE!!!
+ * This function runs inside the RNG thread! Don't do anything silly!
+ */
void
-randomdev_deinit_reader(void)
+random_sources_feed(void)
{
+ uint32_t entropy[HARVESTSIZE];
+ struct random_sources *rrs;
+ u_int i, n, local_read_rate;
+
+ /*
+ * Step over all of live entropy sources, and feed their output
+ * to the system-wide RNG.
+ */
+ /* XXX: FIX!! Next lines as an atomic operation? */
+ local_read_rate = read_rate;
+ read_rate = RANDOM_ALG_READ_RATE_MINIMUM;
+ LIST_FOREACH(rrs, &source_list, rrs_entries) {
+ for (i = 0; i < random_alg_context.ra_poolcount*local_read_rate; i++) {
+ n = rrs->rrs_source->rs_read(entropy, sizeof(entropy));
+ KASSERT((n > 0 && n <= sizeof(entropy)), ("very bad return from rs_read (= %d) in %s", n, __func__));
+ random_harvest_direct(entropy, n, (n*8)/2, rrs->rrs_source->rs_source);
+ }
+ }
+ explicit_bzero(entropy, sizeof(entropy));
+}
- read_func = dummy_random_read_phony;
+static int
+random_source_handler(SYSCTL_HANDLER_ARGS)
+{
+ struct random_sources *rrs;
+ struct sbuf sbuf;
+ int error, count;
+
+ sbuf_new_for_sysctl(&sbuf, NULL, 64, req);
+ count = 0;
+ LIST_FOREACH(rrs, &source_list, rrs_entries) {
+ sbuf_cat(&sbuf, (count++ ? ",'" : "'"));
+ sbuf_cat(&sbuf, rrs->rrs_source->rs_ident);
+ sbuf_cat(&sbuf, "'");
+ }
+ error = sbuf_finish(&sbuf);
+ sbuf_delete(&sbuf);
+ return (error);
}
+SYSCTL_PROC(_kern_random, OID_AUTO, random_sources, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ NULL, 0, random_source_handler, "A",
+ "List of active fast entropy sources.");
+#endif /* !defined(RANDOM_DUMMY) */
-/* 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)
+/* ARGSUSED */
+static int
+randomdev_modevent(module_t mod __unused, int type, void *data __unused)
{
+ int error = 0;
- if (count < 0)
- return 0;
+ switch (type) {
+ case MOD_LOAD:
+ printf("random: entropy device external interface\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 */
+ break;
+ case MOD_UNLOAD:
+ destroy_dev(random_dev);
+ break;
+ case MOD_SHUTDOWN:
+ break;
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+ return (error);
+}
- read_func(buf, count);
+static moduledata_t randomdev_mod = {
+ "random_device",
+ randomdev_modevent,
+ 0
+};
- return count;
-}
+DECLARE_MODULE(random_device, randomdev_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
+MODULE_VERSION(random_device, 1);
diff --git a/sys/dev/random/randomdev.h b/sys/dev/random/randomdev.h
index 4ca88ff..0af741f 100644
--- a/sys/dev/random/randomdev.h
+++ b/sys/dev/random/randomdev.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2000-2013 Mark R V Murray
+ * Copyright (c) 2000-2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,41 +27,87 @@
*/
#ifndef SYS_DEV_RANDOM_RANDOMDEV_H_INCLUDED
-#define SYS_DEV_RANDOM_RANDOMDEV_H_INCLUDED
+#define SYS_DEV_RANDOM_RANDOMDEV_H_INCLUDED
/* This header contains only those definitions that are global
* and non algorithm-specific for the entropy processor
*/
-typedef void random_init_func_t(void);
-typedef void random_deinit_func_t(void);
-
-void randomdev_init_harvester(void (*)(const void *, u_int, u_int, enum random_entropy_source));
-void randomdev_init_reader(void (*)(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 void 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) \
+#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)) \
+ if (*(u_int *)(oidp->oid_arg1) <= (min)) \
*(u_int *)(oidp->oid_arg1) = (min); \
- else if (*(u_int *)(oidp->oid_arg1) > (max)) \
+ 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, \
+ return (sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, \
req)); \
}
#endif /* SYSCTL_DECL */
-#endif
+MALLOC_DECLARE(M_ENTROPY);
+
+#define RANDOM_ALG_READ_RATE_MINIMUM 32
+
+struct harvest_event;
+
+typedef void random_alg_pre_read_t(void);
+typedef void random_alg_read_t(uint8_t *, u_int);
+typedef void random_alg_post_read_t(void);
+typedef void random_alg_write_t(uint8_t *, u_int);
+typedef int random_alg_seeded_t(void);
+typedef void random_alg_reseed_t(void);
+typedef void random_alg_eventprocessor_t(struct harvest_event *);
+
+typedef u_int random_source_read_t(void *, u_int);
+
+/*
+ * Random Algorithm is a processor of randomness for the kernel
+ * and for userland.
+ */
+struct random_algorithm {
+ const char *ra_ident;
+ u_int ra_poolcount;
+ random_alg_pre_read_t *ra_pre_read;
+ random_alg_read_t *ra_read;
+ random_alg_post_read_t *ra_post_read;
+ random_alg_write_t *ra_write;
+ random_alg_reseed_t *ra_reseed;
+ random_alg_seeded_t *ra_seeded;
+ random_alg_eventprocessor_t *ra_event_processor;
+};
+
+extern struct random_algorithm random_alg_context;
+
+/*
+ * Random Source is a source of entropy that can provide
+ * specified or approximate amount of entropy immediately
+ * upon request.
+ */
+struct random_source {
+ const char *rs_ident;
+ enum random_entropy_source rs_source;
+ random_source_read_t *rs_read;
+};
+
+#if !defined(RANDOM_DUMMY)
+struct random_sources {
+ LIST_ENTRY(random_sources) rrs_entries;
+ struct random_source *rrs_source;
+};
+#endif /* !defined(RANDOM_DUMMY) */
+
+void random_source_register(struct random_source *);
+void random_source_deregister(struct random_source *);
+
+void random_sources_feed(void);
+
+void randomdev_unblock(void);
+
+#endif /* SYS_DEV_RANDOM_RANDOMDEV_H_INCLUDED */
diff --git a/sys/dev/random/randomdev_soft.h b/sys/dev/random/randomdev_none.c
index e814de6..ee5cbf2 100644
--- a/sys/dev/random/randomdev_soft.h
+++ b/sys/dev/random/randomdev_none.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2000-2013 Mark R V Murray
+ * Copyright (c) 2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -23,17 +23,50 @@
* (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_RANDOMDEV_SOFT_H_INCLUDED
-#define SYS_DEV_RANDOM_RANDOMDEV_SOFT_H_INCLUDED
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
-/* This header contains only those definitions that are
- * specific to the entropy processor
- */
+#include <sys/param.h>
+#include <sys/malloc.h>
+#include <sys/random.h>
+#include <sys/systm.h>
+
+#include <dev/random/randomdev.h>
-void randomdev_init(void);
-void randomdev_deinit(void);
+#include "opt_random.h"
+#if defined(RANDOM_DUMMY) || defined(RANDOM_YARROW)
+#error "Cannot define any of RANDOM_DUMMY and RANDOM_YARROW without 'device random'"
#endif
+
+/*-
+ * Dummy "not even here" device. Stub out all routines that the kernel would need.
+ */
+
+/* ARGSUSED */
+u_int
+read_random(void *random_buf __unused, u_int len __unused)
+{
+
+ return (0);
+}
+
+/* ARGSUSED */
+void
+random_harvest_direct(const void *entropy __unused, u_int count __unused, u_int bits __unused, enum random_entropy_source origin __unused)
+{
+}
+
+/* ARGSUSED */
+void
+random_harvest_queue(const void *entropy __unused, u_int count __unused, u_int bits __unused, enum random_entropy_source origin __unused)
+{
+}
+
+/* ARGSUSED */
+void
+random_harvest_fast(const void *entropy __unused, u_int count __unused, u_int bits __unused, enum random_entropy_source origin __unused)
+{
+}
diff --git a/sys/dev/random/randomdev_soft.c b/sys/dev/random/randomdev_soft.c
deleted file mode 100644
index 92b112a..0000000
--- a/sys/dev/random/randomdev_soft.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*-
- * Copyright (c) 2000-2014 Mark R V Murray
- * Copyright (c) 2004 Robert N. M. Watson
- * 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.
- *
- */
-
-/*
- * 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)
-#define RANDOM_YARROW
-#elif defined(RANDOM_YARROW) && defined(RANDOM_FORTUNA)
-#error "Must define either RANDOM_YARROW or RANDOM_FORTUNA"
-#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>
-#include <sys/malloc.h>
-#include <sys/module.h>
-#include <sys/mutex.h>
-#include <sys/poll.h>
-#include <sys/random.h>
-#include <sys/sysctl.h>
-#include <sys/unistd.h>
-
-#include <dev/random/randomdev.h>
-#include <dev/random/randomdev_soft.h>
-#include <dev/random/random_harvestq.h>
-#include <dev/random/random_adaptors.h>
-#if defined(RANDOM_YARROW)
-#include <dev/random/yarrow.h>
-#endif
-#if defined(RANDOM_FORTUNA)
-#include <dev/random/fortuna.h>
-#endif
-
-static struct random_adaptor random_soft_processor = {
-#if defined(RANDOM_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)
-#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
- .ra_init = randomdev_init,
- .ra_deinit = randomdev_deinit,
-};
-
-void
-randomdev_init(void)
-{
-
-#if defined(RANDOM_YARROW)
- random_yarrow_init_alg();
- random_harvestq_init(random_yarrow_process_event, 2);
-#endif
-#if defined(RANDOM_FORTUNA)
- random_fortuna_init_alg();
- random_harvestq_init(random_fortuna_process_event, 32);
-#endif
-
- /* Register the randomness harvesting routine */
- randomdev_init_harvester(random_harvestq_internal);
-}
-
-void
-randomdev_deinit(void)
-{
- /* Deregister the randomness harvesting routine */
- randomdev_deinit_harvester();
-
-#if defined(RANDOM_YARROW)
- random_yarrow_deinit_alg();
-#endif
-#if defined(RANDOM_FORTUNA)
- random_fortuna_deinit_alg();
-#endif
-}
-
-/* ARGSUSED */
-static int
-randomdev_soft_modevent(module_t mod __unused, int type, void *unused __unused)
-{
- int error = 0;
-
- switch (type) {
- case MOD_LOAD:
- printf("random: SOFT: %s init()\n", RANDOM_CSPRNG_NAME);
- random_adaptor_register(RANDOM_CSPRNG_NAME, &random_soft_processor);
- break;
-
- case MOD_UNLOAD:
- random_adaptor_deregister(RANDOM_CSPRNG_NAME);
- break;
-
- case MOD_SHUTDOWN:
- break;
-
- default:
- error = EOPNOTSUPP;
- break;
-
- }
- return (error);
-}
-
-#if defined(RANDOM_YARROW)
-DEV_MODULE(yarrow, randomdev_soft_modevent, NULL);
-MODULE_VERSION(yarrow, 1);
-MODULE_DEPEND(yarrow, randomdev, 1, 1, 1);
-#endif
-#if defined(RANDOM_FORTUNA)
-DEV_MODULE(fortuna, randomdev_soft_modevent, NULL);
-MODULE_VERSION(fortuna, 1);
-MODULE_DEPEND(fortuna, randomdev, 1, 1, 1);
-#endif
diff --git a/sys/dev/random/uint128.h b/sys/dev/random/uint128.h
index b2cc1e0..22380b2 100644
--- a/sys/dev/random/uint128.h
+++ b/sys/dev/random/uint128.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2014 Mark R V Murray
+ * Copyright (c) 2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,7 +27,7 @@
*/
#ifndef SYS_DEV_RANDOM_UINT128_H_INCLUDED
-#define SYS_DEV_RANDOM_UINT128_H_INCLUDED
+#define SYS_DEV_RANDOM_UINT128_H_INCLUDED
/* This whole thing is a crock :-(
*
@@ -35,40 +35,41 @@
*/
#ifdef __SIZEOF_INT128__
-typedef __uint128_t uint128_t;
-#else
-typedef uint64_t uint128_t[2];
+#define USE_REAL_UINT128_T
#endif
-static __inline void
-uint128_clear(uint128_t *big_uint)
-{
-#ifdef __SIZEOF_INT128__
- (*big_uint) = 0ULL;
+#ifdef USE_REAL_UINT128_T
+typedef __uint128_t uint128_t;
+#define UINT128_ZERO 0ULL
#else
- (*big_uint)[0] = (*big_uint)[1] = 0UL;
+typedef struct {
+ /* Ignore endianness */
+ uint64_t u128t_word0;
+ uint64_t u128t_word1;
+} uint128_t;
+static const uint128_t very_long_zero = {0UL,0UL};
+#define UINT128_ZERO very_long_zero
#endif
-}
static __inline void
-uint128_increment(uint128_t *big_uint)
+uint128_increment(uint128_t *big_uintp)
{
-#ifdef __SIZEOF_INT128__
- (*big_uint)++;
+#ifdef USE_REAL_UINT128_T
+ (*big_uintp)++;
#else
- (*big_uint)[0]++;
- if ((*big_uint)[0] == 0UL)
- (*big_uint)[1]++;
+ big_uintp->u128t_word0++;
+ if (big_uintp->u128t_word0 == 0UL)
+ big_uintp->u128t_word1++;
#endif
}
static __inline int
uint128_is_zero(uint128_t big_uint)
{
-#ifdef __SIZEOF_INT128__
- return (big_uint == 0ULL);
+#ifdef USE_REAL_UINT128_T
+ return (big_uint == UINT128_ZERO);
#else
- return (big_uint[0] == 0UL && big_uint[1] == 0UL);
+ return (big_uint.u128t_word0 == 0UL && big_uint.u128t_word1 == 0UL);
#endif
}
diff --git a/sys/dev/random/unit_test.c b/sys/dev/random/unit_test.c
index 32b3363..80b32cf 100644
--- a/sys/dev/random/unit_test.c
+++ b/sys/dev/random/unit_test.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2000-2013 Mark R V Murray
+ * Copyright (c) 2000-2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -37,6 +37,7 @@ cc -g -O0 -pthread -DRANDOM_<alg> -DRANDOM_DEBUG -I../.. -lstdthreads -Wall \
../../crypto/rijndael/rijndael-api-fst.c \
../../crypto/rijndael/rijndael-alg-fst.c \
../../crypto/sha2/sha2.c \
+ -lz \
-o unit_test
./unit_test
@@ -49,6 +50,7 @@ Where <alg> is YARROW or FORTUNA.
#include <stdlib.h>
#include <threads.h>
#include <unistd.h>
+#include <zlib.h>
#include "unit_test.h"
@@ -59,10 +61,77 @@ Where <alg> is YARROW or FORTUNA.
#include "dev/random/fortuna.h"
#endif
-#define NUM_THREADS 3
+#define NUM_THREADS 3
+#define DEBUG
static volatile int stopseeding = 0;
+static __inline void
+check_err(int err, const char *func)
+{
+ if (err != Z_OK) {
+ fprintf(stderr, "Compress error in %s: %d\n", func, err);
+ exit(0);
+ }
+}
+
+void *
+myalloc(void *q, unsigned n, unsigned m)
+{
+ q = Z_NULL;
+ return (calloc(n, m));
+}
+
+void myfree(void *q, void *p)
+{
+ q = Z_NULL;
+ free(p);
+}
+
+size_t
+block_deflate(uint8_t *uncompr, uint8_t *compr, const size_t len)
+{
+ z_stream c_stream;
+ int err;
+
+ if (len == 0)
+ return (0);
+
+ c_stream.zalloc = myalloc;
+ c_stream.zfree = myfree;
+ c_stream.opaque = NULL;
+
+ err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
+ check_err(err, "deflateInit");
+
+ c_stream.next_in = uncompr;
+ c_stream.next_out = compr;
+ c_stream.avail_in = len;
+ c_stream.avail_out = len*2u +512u;
+
+ while (c_stream.total_in != len && c_stream.total_out < (len*2u + 512u)) {
+ err = deflate(&c_stream, Z_NO_FLUSH);
+#ifdef DEBUG
+ printf("deflate: len = %zd total_in = %lu total_out = %lu\n", len, c_stream.total_in, c_stream.total_out);
+#endif
+ check_err(err, "deflate(..., Z_NO_FLUSH)");
+ }
+
+ for (;;) {
+ err = deflate(&c_stream, Z_FINISH);
+#ifdef DEBUG
+ printf("deflate: len = %zd total_in = %lu total_out = %lu\n", len, c_stream.total_in, c_stream.total_out);
+#endif
+ if (err == Z_STREAM_END) break;
+ check_err(err, "deflate(..., Z_STREAM_END)");
+ }
+
+ err = deflateEnd(&c_stream);
+ check_err(err, "deflateEnd");
+
+ return ((size_t)c_stream.total_out);
+}
+
void
random_adaptor_unblock(void)
{
@@ -128,6 +197,7 @@ WriteCSPRNG(void *threadid)
if (i % 1000 == 0)
printf("Thread write 1 - %d\n", i);
if (buf != NULL) {
+ printf("Thread 1 writing.\n");
#ifdef RANDOM_YARROW
random_yarrow_write(buf, i);
#endif
@@ -149,9 +219,12 @@ WriteCSPRNG(void *threadid)
static int
ReadCSPRNG(void *threadid)
{
- size_t tid;
- uint8_t *buf;
+ size_t tid, zsize;
+ uint8_t *buf, *zbuf;
int i;
+#ifdef DEBUG
+ int j;
+#endif
tid = (size_t)threadid;
printf("Thread #%zd starts\n", tid);
@@ -164,42 +237,50 @@ ReadCSPRNG(void *threadid)
#endif
{
#ifdef RANDOM_YARROW
- random_yarrow_read(NULL, 0);
- random_yarrow_read(NULL, 1);
+ random_yarrow_pre_read();
+ random_yarrow_post_read();
#endif
#ifdef RANDOM_FORTUNA
- random_fortuna_read(NULL, 0);
- random_fortuna_read(NULL, 1);
+ random_fortuna_pre_read();
+ random_fortuna_post_read();
#endif
usleep(100);
}
for (i = 0; i < 100000; i++) {
buf = malloc(i);
+ zbuf = malloc(2*i + 1024);
if (i % 1000 == 0)
- printf("Thread read %zd - %d %p\n", tid, i, buf);
- if (buf != NULL) {
+ printf("Thread read %zd - %d\n", tid, i);
+ if (buf != NULL && zbuf != NULL) {
#ifdef RANDOM_YARROW
- random_yarrow_read(NULL, 0);
+ random_yarrow_pre_read();
random_yarrow_read(buf, i);
- random_yarrow_read(NULL, 1);
+ random_yarrow_post_read();
#endif
#ifdef RANDOM_FORTUNA
- random_fortuna_read(NULL, 0);
+ random_fortuna_pre_read();
random_fortuna_read(buf, i);
- random_fortuna_read(NULL, 1);
+ random_fortuna_post_read();
#endif
-#if 0
- {
- int j;
-
+ zsize = block_deflate(buf, zbuf, i);
+ if (zsize < i)
+ printf("ERROR!! Compressible RNG output!\n");
+#ifdef DEBUG
+ printf("RNG output:\n");
for (j = 0; j < i; j++) {
printf(" %02X", buf[j]);
if (j % 32 == 31 || j == i - 1)
printf("\n");
}
+ printf("Compressed output:\n");
+ for (j = 0; j < zsize; j++) {
+ printf(" %02X", zbuf[j]);
+ if (j % 32 == 31 || j == zsize - 1)
+ printf("\n");
}
#endif
+ free(zbuf);
free(buf);
}
usleep(100);
@@ -228,7 +309,7 @@ main(int argc, char *argv[])
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);
+ rc = thrd_create(&threads[t], (t == 0 ? RunHarvester : (t == 1 ? WriteCSPRNG : ReadCSPRNG)), NULL);
if (rc != thrd_success) {
printf("ERROR; return code from thrd_create() is %d\n", rc);
exit(-1);
diff --git a/sys/dev/random/unit_test.h b/sys/dev/random/unit_test.h
index 9fc0931..648d294 100644
--- a/sys/dev/random/unit_test.h
+++ b/sys/dev/random/unit_test.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2013 Mark R V Murray
+ * Copyright (c) 2013-2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,20 +28,39 @@
#ifndef UNIT_TEST_H_INCLUDED
-#define UNIT_TEST_H_INCLUDED
+#define UNIT_TEST_H_INCLUDED
+
+#ifdef _KERNEL
+#error "Random unit tests cannot be compiled into the kernel."
+#endif
void random_adaptor_unblock(void);
+#if defined(clang) && __has_builtin(__builtin_readcyclecounter)
+#define rdtsc __builtin_readcyclecounter
+#else /* !clang */
+#if defined(__amd64__) || defined(__i386__)
+static __inline uint64_t
+rdtsc(void)
+{
+ uint32_t low, high;
+
+ __asm __volatile("rdtsc" : "=a" (low), "=d" (high));
+ return (low | ((uint64_t)high << 32));
+}
+#else /* __amd64__ || __i386__ */
+#error "No rdtsc() implementation available."
+#endif /* __amd64__ || __i386__ */
+#endif /* !clang */
+
static __inline uint64_t
get_cyclecount(void)
{
- /* Shaddup! */
- return (4ULL);
+ return (rdtsc());
}
-// #define PAGE_SIZE 4096
-#define HARVESTSIZE 16
+#define HARVESTSIZE 2
enum random_entropy_source {
RANDOM_START = 0,
@@ -51,7 +70,7 @@ enum random_entropy_source {
struct harvest_event {
uintmax_t he_somecounter; /* fast counter for clock jitter */
- uint8_t he_entropy[HARVESTSIZE];/* some harvested entropy */
+ uint32_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 */
diff --git a/sys/dev/random/yarrow.c b/sys/dev/random/yarrow.c
index 88e09af..540d643 100644
--- a/sys/dev/random/yarrow.c
+++ b/sys/dev/random/yarrow.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2000-2013 Mark R V Murray
+ * Copyright (c) 2000-2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,12 +29,12 @@
__FBSDID("$FreeBSD$");
#ifdef _KERNEL
-#include "opt_random.h"
-
#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/mutex.h>
#include <sys/random.h>
#include <sys/sysctl.h>
@@ -47,13 +47,10 @@ __FBSDID("$FreeBSD$");
#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/yarrow.h>
#else /* !_KERNEL */
-#include <sys/param.h>
-#include <sys/types.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
@@ -66,467 +63,403 @@ __FBSDID("$FreeBSD$");
#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 RANDOM_YARROW_TIMEBIN 16 /* max value for Pt/t */
-#define FAST 0
-#define SLOW 1
+#define RANDOM_YARROW_FAST 0
+#define RANDOM_YARROW_SLOW 1
+#define RANDOM_YARROW_NPOOLS 2
-/* This algorithm (and code) presumes that KEYSIZE is twice as large as BLOCKSIZE */
-CTASSERT(BLOCKSIZE == sizeof(uint128_t));
-CTASSERT(KEYSIZE == 2*BLOCKSIZE);
+/* This algorithm (and code) presumes that RANDOM_KEYSIZE is twice as large as RANDOM_BLOCKSIZE */
+CTASSERT(RANDOM_BLOCKSIZE == sizeof(uint128_t));
+CTASSERT(RANDOM_KEYSIZE == 2*RANDOM_BLOCKSIZE);
-/* This is the beastie that needs protecting. It contains all of the
- * state that we are excited about.
- * Exactly one is instantiated.
+/*
+ * This is the beastie that needs protecting. It contains all of the
+ * state that we are excited about. Exactly one is instantiated.
*/
static struct yarrow_state {
- union {
- uint8_t byte[BLOCKSIZE];
- 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];/* ... per source */
- u_int thresh; /* pool reseed threshhold */
- struct randomdev_hash hash; /* accumulated entropy */
- } 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;
+ uint128_t ys_counter; /* C */
+ struct randomdev_key ys_key; /* K */
+ u_int ys_gengateinterval; /* Pg */
+ u_int ys_bins; /* Pt/t */
+ u_int ys_outputblocks; /* count output blocks for gates */
+ u_int ys_slowoverthresh; /* slow pool overthreshhold reseed count */
+ struct ys_pool {
+ u_int ysp_source_bits[ENTROPYSOURCE]; /* estimated bits of entropy per source */
+ u_int ysp_thresh; /* pool reseed threshhold */
+ struct randomdev_hash ysp_hash; /* accumulated entropy */
+ } ys_pool[RANDOM_YARROW_NPOOLS];/* pool[0] is fast, pool[1] is slow */
+ int ys_seeded;
+ /* Reseed lock */
+ mtx_t ys_mtx;
} 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(bins, RANDOM_YARROW_NPOOLS, 16);
+RANDOM_CHECK_UINT(fastthresh, (RANDOM_BLOCKSIZE*8)/4, (RANDOM_BLOCKSIZE*8)); /* Bit counts */
+RANDOM_CHECK_UINT(slowthresh, (RANDOM_BLOCKSIZE*8)/4, (RANDOM_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);
+static void random_yarrow_pre_read(void);
+static void random_yarrow_read(uint8_t *, u_int);
+static void random_yarrow_post_read(void);
+static void random_yarrow_write(uint8_t *, u_int);
+static void random_yarrow_reseed(void);
+static int random_yarrow_seeded(void);
+static void random_yarrow_reseed_internal(u_int);
+static void random_yarrow_process_event(struct harvest_event *);
-void
-random_yarrow_init_alg(void)
+#ifdef _KERNEL
+/* Interface to Adaptors system */
+struct random_algorithm random_alg_context = {
+ .ra_ident = "Yarrow",
+ .ra_pre_read = random_yarrow_pre_read,
+ .ra_read = random_yarrow_read,
+ .ra_post_read = random_yarrow_post_read,
+ .ra_write = random_yarrow_write,
+ .ra_reseed = random_yarrow_reseed,
+ .ra_seeded = random_yarrow_seeded,
+ .ra_event_processor = random_yarrow_process_event,
+ .ra_poolcount = RANDOM_YARROW_NPOOLS,
+};
+#endif
+
+/* ARGSUSED */
+static void
+random_yarrow_init_alg(void *unused __unused)
{
int i, j;
#ifdef _KERNEL
struct sysctl_oid *random_yarrow_o;
-#endif /* _KERNEL */
-
- memset(yarrow_state.start_cache.junk, 0, KEYSIZE);
- randomdev_hash_init(&yarrow_state.start_cache.hash);
-
- /* 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 */
+#endif
+ RANDOM_RESEED_INIT_LOCK();
/* Start unseeded, therefore blocked. */
- yarrow_state.seeded = 0;
-
+ yarrow_state.ys_seeded = 0;
#ifdef _KERNEL
- /* Yarrow parameters. Do not adjust these unless you have
+ /*
+ * Yarrow parameters. Do not adjust these unless you have
* have a very good clue about what they do!
*/
random_yarrow_o = SYSCTL_ADD_NODE(&random_clist,
SYSCTL_STATIC_CHILDREN(_kern_random),
OID_AUTO, "yarrow", CTLFLAG_RW, 0,
"Yarrow Parameters");
-
SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
- "gengateinterval", CTLTYPE_INT|CTLFLAG_RW,
- &yarrow_state.gengateinterval, 10,
- random_check_uint_gengateinterval, "I",
+ "gengateinterval", CTLTYPE_UINT | CTLFLAG_RWTUN,
+ &yarrow_state.ys_gengateinterval, 0,
+ random_check_uint_gengateinterval, "UI",
"Generation gate interval");
-
SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
- "bins", CTLTYPE_INT|CTLFLAG_RW,
- &yarrow_state.bins, 10,
- random_check_uint_bins, "I",
+ "bins", CTLTYPE_UINT | CTLFLAG_RWTUN,
+ &yarrow_state.ys_bins, 0,
+ random_check_uint_bins, "UI",
"Execution time tuner");
-
SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
- "fastthresh", CTLTYPE_INT|CTLFLAG_RW,
- &yarrow_state.pool[0].thresh, (3*(BLOCKSIZE*8))/4,
- random_check_uint_fastthresh, "I",
+ "fastthresh", CTLTYPE_UINT | CTLFLAG_RWTUN,
+ &yarrow_state.ys_pool[0].ysp_thresh, 0,
+ random_check_uint_fastthresh, "UI",
"Fast reseed threshold");
-
SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
- "slowthresh", CTLTYPE_INT|CTLFLAG_RW,
- &yarrow_state.pool[1].thresh, (BLOCKSIZE*8),
- random_check_uint_slowthresh, "I",
+ "slowthresh", CTLTYPE_UINT | CTLFLAG_RWTUN,
+ &yarrow_state.ys_pool[1].ysp_thresh, 0,
+ random_check_uint_slowthresh, "UI",
"Slow reseed threshold");
-
SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
- "slowoverthresh", CTLTYPE_INT|CTLFLAG_RW,
- &yarrow_state.slowoverthresh, 2,
- random_check_uint_slowoverthresh, "I",
+ "slowoverthresh", CTLTYPE_UINT | CTLFLAG_RWTUN,
+ &yarrow_state.ys_slowoverthresh, 0,
+ random_check_uint_slowoverthresh, "UI",
"Slow over-threshold reseed");
#endif /* _KERNEL */
-
- 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;
-
+ yarrow_state.ys_gengateinterval = 10;
+ yarrow_state.ys_bins = 10;
+ yarrow_state.ys_pool[RANDOM_YARROW_FAST].ysp_thresh = (3*(RANDOM_BLOCKSIZE*8))/4;
+ yarrow_state.ys_pool[RANDOM_YARROW_SLOW].ysp_thresh = (RANDOM_BLOCKSIZE*8);
+ yarrow_state.ys_slowoverthresh = 2;
/* Ensure that the first time we read, we are gated. */
- yarrow_state.outputblocks = yarrow_state.gengateinterval;
-
+ yarrow_state.ys_outputblocks = yarrow_state.ys_gengateinterval;
/* Initialise the fast and slow entropy pools */
- for (i = FAST; i <= SLOW; i++) {
- randomdev_hash_init(&yarrow_state.pool[i].hash);
+ for (i = RANDOM_YARROW_FAST; i <= RANDOM_YARROW_SLOW; i++) {
+ randomdev_hash_init(&yarrow_state.ys_pool[i].ysp_hash);
for (j = RANDOM_START; j < ENTROPYSOURCE; j++)
- yarrow_state.pool[i].source[j].bits = 0U;
+ yarrow_state.ys_pool[i].ysp_source_bits[j] = 0;
}
-
/* Clear the counter */
- uint128_clear(&yarrow_state.counter.whole);
+ yarrow_state.ys_counter = UINT128_ZERO;
}
+#ifdef _KERNEL
+SYSINIT(random_yarrow, SI_SUB_RANDOM, SI_ORDER_THIRD, random_yarrow_init_alg, NULL);
+#endif
-void
-random_yarrow_deinit_alg(void)
+/* ARGSUSED */
+static void
+random_yarrow_deinit_alg(void *unused __unused)
{
- mtx_destroy(&random_reseed_mtx);
- memset(&yarrow_state, 0, sizeof(yarrow_state));
-
+ RANDOM_RESEED_DEINIT_LOCK();
+ explicit_bzero(&yarrow_state, sizeof(yarrow_state));
#ifdef _KERNEL
sysctl_ctx_free(&random_clist);
#endif
}
+#ifdef _KERNEL
+SYSUNINIT(random_yarrow, SI_SUB_RANDOM, SI_ORDER_THIRD, random_yarrow_deinit_alg, NULL);
+#endif
-static __inline void
-random_yarrow_post_insert(void)
+/* Process a single stochastic event off the harvest queue */
+static void
+random_yarrow_process_event(struct harvest_event *event)
{
- u_int pl, overthreshhold[2];
+ u_int pl, overthreshhold[RANDOM_YARROW_NPOOLS];
enum random_entropy_source src;
-#ifdef _KERNEL
- mtx_assert(&random_reseed_mtx, MA_OWNED);
-#endif
+ RANDOM_RESEED_LOCK();
+ /*
+ * 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 % RANDOM_YARROW_NPOOLS;
+ randomdev_hash_iterate(&yarrow_state.ys_pool[pl].ysp_hash, event, sizeof(*event));
+ yarrow_state.ys_pool[pl].ysp_source_bits[event->he_source] += event->he_bits;
/* Count the over-threshold sources in each pool */
- for (pl = 0; pl < 2; pl++) {
+ for (pl = RANDOM_YARROW_FAST; pl <= RANDOM_YARROW_SLOW; pl++) {
overthreshhold[pl] = 0;
for (src = RANDOM_START; src < ENTROPYSOURCE; src++) {
- if (yarrow_state.pool[pl].source[src].bits > yarrow_state.pool[pl].thresh)
+ if (yarrow_state.ys_pool[pl].ysp_source_bits[src] > yarrow_state.ys_pool[pl].ysp_thresh)
overthreshhold[pl]++;
}
}
-
- /* If enough slow sources are over threshhold, then slow reseed
+ /*
+ * 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);
+ if (overthreshhold[RANDOM_YARROW_SLOW] >= yarrow_state.ys_slowoverthresh)
+ random_yarrow_reseed_internal(RANDOM_YARROW_SLOW);
+ else if (overthreshhold[RANDOM_YARROW_FAST] > 0 && yarrow_state.ys_seeded)
+ random_yarrow_reseed_internal(RANDOM_YARROW_FAST);
+ explicit_bzero(event, sizeof(*event));
+ RANDOM_RESEED_UNLOCK();
}
-/* Process a block of data suspected to be slightly stochastic */
+/* Process a block of data suspected to be slightly stochastic. */
static void
-random_yarrow_process_buffer(uint8_t *buf, u_int length)
+random_yarrow_process_buffer(uint32_t *buf, u_int wordcount)
{
static struct harvest_event event;
- u_int i, pl;
+ static u_int destination = 0;
+ int i;
- /* 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 */
+ for (i = 0; i < wordcount; i += sizeof(event.he_entropy)/sizeof(event.he_entropy[0])) {
+ event.he_somecounter = (uint32_t)get_cyclecount();
+ event.he_size = sizeof(event.he_entropy);
+ event.he_bits = event.he_size/8;
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
+ event.he_destination = destination++; /* Harmless cheating */
+ memcpy(event.he_entropy, buf + i, sizeof(event.he_entropy));
+ random_yarrow_process_event(&event);
}
- for (pl = FAST; pl <= SLOW; pl++)
- yarrow_state.pool[pl].source[RANDOM_CACHED].bits += (length >> 4);
-
- random_yarrow_post_insert();
}
static void
-reseed(u_int fastslow)
+random_yarrow_reseed_internal(u_int fastslow)
{
- /* Interrupt-context stack is a limited resource; make large
+ /*
+ * Interrupt-context stack is a limited resource; make large
* structures static.
*/
- static uint8_t v[TIMEBIN][KEYSIZE]; /* v[i] */
- static uint8_t hash[KEYSIZE]; /* h' */
- static uint8_t temp[KEYSIZE];
+ static uint8_t v[RANDOM_YARROW_TIMEBIN][RANDOM_KEYSIZE]; /* v[i] */
+ static uint128_t temp;
static struct randomdev_hash context;
u_int i;
enum random_entropy_source j;
- KASSERT(yarrow_state.pool[FAST].thresh > 0, ("random: Yarrow fast threshold = 0"));
- KASSERT(yarrow_state.pool[SLOW].thresh > 0, ("random: Yarrow slow threshold = 0"));
-
+ KASSERT(yarrow_state.ys_pool[RANDOM_YARROW_FAST].ysp_thresh > 0, ("random: Yarrow fast threshold = 0"));
+ KASSERT(yarrow_state.ys_pool[RANDOM_YARROW_SLOW].ysp_thresh > 0, ("random: Yarrow slow threshold = 0"));
+ RANDOM_RESEED_ASSERT_LOCK_OWNED();
#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");
- }
+ /* WARNING! This is dangerously tedious to do with mutexes held! */
+ printf("random: %s %s seeded = %d\n", __func__, (fastslow == RANDOM_YARROW_FAST ? "RANDOM_YARROW_FAST" : "RANDOM_YARROW_SLOW"), yarrow_state.ys_seeded);
+ printf("random: %s - fast - thresh %d,1 - ", __func__, yarrow_state.ys_pool[RANDOM_YARROW_FAST].ysp_thresh);
+ for (i = RANDOM_START; i < ENTROPYSOURCE; i++)
+ printf(" %d", yarrow_state.ys_pool[RANDOM_YARROW_FAST].ysp_source_bits[i]);
+ printf("\n");
+ printf("random: %s - slow - thresh %d,%d - ", __func__, yarrow_state.ys_pool[RANDOM_YARROW_SLOW].ysp_thresh, yarrow_state.ys_slowoverthresh);
+ for (i = RANDOM_START; i < ENTROPYSOURCE; i++)
+ printf(" %d", yarrow_state.ys_pool[RANDOM_YARROW_SLOW].ysp_source_bits[i]);
+ 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_finish(&yarrow_state.pool[SLOW].hash, temp);
- randomdev_hash_iterate(&context, temp, sizeof(temp));
+ if (fastslow == RANDOM_YARROW_SLOW) {
+ randomdev_hash_finish(&yarrow_state.ys_pool[RANDOM_YARROW_SLOW].ysp_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(&yarrow_state.ys_pool[RANDOM_YARROW_FAST].ysp_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
+ /*-
+ * 2. Compute hash values for all v. _Supposed_ to be computationally
* intensive.
*/
-
- if (yarrow_state.bins > TIMEBIN)
- yarrow_state.bins = TIMEBIN;
- for (i = 1; i < yarrow_state.bins; i++) {
+ if (yarrow_state.ys_bins > RANDOM_YARROW_TIMEBIN)
+ yarrow_state.ys_bins = RANDOM_YARROW_TIMEBIN;
+ for (i = 1; i < yarrow_state.ys_bins; i++) {
randomdev_hash_init(&context);
/* v[i] #= h(v[i - 1]) */
- randomdev_hash_iterate(&context, v[i - 1], KEYSIZE);
+ randomdev_hash_iterate(&context, v[i - 1], RANDOM_KEYSIZE);
/* v[i] #= h(v[0]) */
- randomdev_hash_iterate(&context, v[0], KEYSIZE);
+ randomdev_hash_iterate(&context, v[0], RANDOM_KEYSIZE);
/* v[i] #= h(i) */
randomdev_hash_iterate(&context, &i, sizeof(i));
/* Return the hashval */
randomdev_hash_finish(&context, v[i]);
}
-
- /* 3. Compute a new key; h' is the identity function here;
+ /*-
+ * 3. Compute a new key; h' is the identity function here;
* it is not being ignored!
*/
-
randomdev_hash_init(&context);
- 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(&yarrow_state.key, temp);
-
+ randomdev_hash_iterate(&context, &yarrow_state.ys_key, RANDOM_KEYSIZE);
+ for (i = 1; i < yarrow_state.ys_bins; i++)
+ randomdev_hash_iterate(&context, v[i], RANDOM_KEYSIZE);
+ randomdev_hash_finish(&context, &temp);
+ randomdev_encrypt_init(&yarrow_state.ys_key, &temp);
/* 4. Recompute the counter */
-
- uint128_clear(&yarrow_state.counter.whole);
- randomdev_encrypt(&yarrow_state.key, yarrow_state.counter.byte, temp, BLOCKSIZE);
- memcpy(yarrow_state.counter.byte, temp, BLOCKSIZE);
-
+ yarrow_state.ys_counter = UINT128_ZERO;
+ randomdev_encrypt(&yarrow_state.ys_key, &yarrow_state.ys_counter, &temp, RANDOM_BLOCKSIZE);
+ yarrow_state.ys_counter = temp;
/* 5. Reset entropy estimate accumulators to zero */
-
for (i = 0; i <= fastslow; i++)
for (j = RANDOM_START; j < ENTROPYSOURCE; j++)
- yarrow_state.pool[i].source[j].bits = 0;
-
+ yarrow_state.ys_pool[i].ysp_source_bits[j] = 0;
/* 6. Wipe memory of intermediate values */
-
- 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 */
-
- /* This pseudo-code is documentation. Please leave it alone. */
+ explicit_bzero(v, sizeof(v));
+ explicit_bzero(&temp, sizeof(temp));
+ explicit_bzero(&context, sizeof(context));
+/* Not defined so writes ain't gonna happen. Kept for documenting. */
+#ifdef RANDOM_RWFILE_WRITE_IS_OK
+ /*-
+ * 7. Dump to seed file.
+ * 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
-
/* Unblock the device if it was blocked due to being unseeded */
- if (!yarrow_state.seeded) {
- yarrow_state.seeded = 1;
- random_adaptor_unblock();
+ if (!yarrow_state.ys_seeded) {
+ yarrow_state.ys_seeded = 1;
+ randomdev_unblock();
}
}
-/* Internal function to return processed entropy from the PRNG */
+static __inline void
+random_yarrow_generator_gate(void)
+{
+ u_int i;
+ uint8_t temp[RANDOM_KEYSIZE];
+
+ RANDOM_RESEED_ASSERT_LOCK_OWNED();
+ uint128_increment(&yarrow_state.ys_counter);
+ for (i = 0; i < RANDOM_KEYSIZE; i += RANDOM_BLOCKSIZE)
+ randomdev_encrypt(&yarrow_state.ys_key, &yarrow_state.ys_counter, temp + i, RANDOM_BLOCKSIZE);
+ randomdev_encrypt_init(&yarrow_state.ys_key, temp);
+ explicit_bzero(temp, sizeof(temp));
+}
+
+/*-
+ * Used to return processed entropy from the PRNG.
+ * There is a pre_read and a post_read required to be present
+ * (but they can be null functions) in order to allow specific
+ * actions at the begin or the end of a read. Yarrow does its
+ * reseeding in its own thread. The _pre_read() and _post_read()
+ * are not used here, and must be kept for completeness.
+ */
+void
+random_yarrow_pre_read(void)
+{
+}
+
+/*-
+ * Main read from Yarrow.
+ * The supplied buf MUST be a multiple (>=0) of RANDOM_BLOCKSIZE in size.
+ * Lots of code presumes this for efficiency, both here and in other
+ * routines. You are NOT allowed to break this!
+ */
void
random_yarrow_read(uint8_t *buf, u_int bytecount)
{
- uint8_t tbuf[BLOCKSIZE];
u_int blockcount, i;
- /* Check for initial/final read requests */
- if (buf == NULL)
- return;
-
- /* The reseed task must not be jumped on */
- mtx_lock(&random_reseed_mtx);
-
- blockcount = (bytecount + BLOCKSIZE - 1)/BLOCKSIZE;
+ RANDOM_RESEED_LOCK();
+ blockcount = (bytecount + RANDOM_BLOCKSIZE - 1)/RANDOM_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);
- if ((i + 1) * BLOCKSIZE > bytecount) {
- /* TODO: FIX! remove memcpy()! */
- randomdev_encrypt(&yarrow_state.key,
- yarrow_state.counter.byte, tbuf, BLOCKSIZE);
- memcpy(buf, tbuf, bytecount - i * BLOCKSIZE);
- } else {
- randomdev_encrypt(&yarrow_state.key,
- yarrow_state.counter.byte, buf, BLOCKSIZE);
- buf += BLOCKSIZE;
+ if (yarrow_state.ys_outputblocks++ >= yarrow_state.ys_gengateinterval) {
+ random_yarrow_generator_gate();
+ yarrow_state.ys_outputblocks = 0;
}
+ uint128_increment(&yarrow_state.ys_counter);
+ randomdev_encrypt(&yarrow_state.ys_key, &yarrow_state.ys_counter, buf, RANDOM_BLOCKSIZE);
+ buf += RANDOM_BLOCKSIZE;
}
-
- mtx_unlock(&random_reseed_mtx);
+ RANDOM_RESEED_UNLOCK();
}
-/* Internal function to hand external entropy to the PRNG */
void
-random_yarrow_write(uint8_t *buf, u_int count)
+random_yarrow_post_read(void)
{
- 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);
+ /* CWOT */
}
-static void
-generator_gate(void)
+/* Internal function to hand external entropy to the PRNG. */
+void
+random_yarrow_write(uint8_t *buf, u_int count)
{
- u_int i;
- uint8_t temp[KEYSIZE];
-
- for (i = 0; i < KEYSIZE; i += BLOCKSIZE) {
- uint128_increment(&yarrow_state.counter.whole);
- randomdev_encrypt(&yarrow_state.key, yarrow_state.counter.byte, temp + i, BLOCKSIZE);
- }
-
- randomdev_encrypt_init(&yarrow_state.key, temp);
- memset(temp, 0, KEYSIZE);
+ struct randomdev_hash hash;
+ uint32_t entropy_data[RANDOM_KEYSIZE_WORDS], timestamp;
+
+ /* Extra timing here is helpful to scrape scheduler timing entropy */
+ randomdev_hash_init(&hash);
+ timestamp = (uint32_t)get_cyclecount();
+ randomdev_hash_iterate(&hash, &timestamp, sizeof(timestamp));
+ randomdev_hash_iterate(&hash, buf, count);
+ timestamp = (uint32_t)get_cyclecount();
+ randomdev_hash_iterate(&hash, &timestamp, sizeof(timestamp));
+ randomdev_hash_finish(&hash, entropy_data);
+ explicit_bzero(&hash, sizeof(hash));
+ random_yarrow_process_buffer(entropy_data, sizeof(entropy_data)/sizeof(entropy_data[0]));
+ explicit_bzero(entropy_data, sizeof(entropy_data));
}
void
random_yarrow_reseed(void)
{
- mtx_lock(&random_reseed_mtx);
- reseed(SLOW);
- mtx_unlock(&random_reseed_mtx);
+ RANDOM_RESEED_LOCK();
+ random_yarrow_reseed_internal(RANDOM_YARROW_SLOW);
+ RANDOM_RESEED_UNLOCK();
}
int
random_yarrow_seeded(void)
{
- return (yarrow_state.seeded);
+ return (yarrow_state.ys_seeded);
}
-
-#endif /* RANDOM_YARROW */
diff --git a/sys/dev/random/yarrow.h b/sys/dev/random/yarrow.h
index 9ba0b4e..a08d107 100644
--- a/sys/dev/random/yarrow.h
+++ b/sys/dev/random/yarrow.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2000-2013 Mark R V Murray
+ * Copyright (c) 2000-2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,18 +27,21 @@
*/
#ifndef SYS_DEV_RANDOM_YARROW_H_INCLUDED
-#define SYS_DEV_RANDOM_YARROW_H_INCLUDED
+#define SYS_DEV_RANDOM_YARROW_H_INCLUDED
#ifdef _KERNEL
typedef struct mtx mtx_t;
+#define RANDOM_RESEED_INIT_LOCK(x) mtx_init(&yarrow_state.ys_mtx, "reseed mutex", NULL, MTX_DEF)
+#define RANDOM_RESEED_DEINIT_LOCK(x) mtx_destroy(&yarrow_state.ys_mtx)
+#define RANDOM_RESEED_LOCK(x) mtx_lock(&yarrow_state.ys_mtx)
+#define RANDOM_RESEED_UNLOCK(x) mtx_unlock(&yarrow_state.ys_mtx)
+#define RANDOM_RESEED_ASSERT_LOCK_OWNED(x) mtx_assert(&yarrow_state.ys_mtx, MA_OWNED)
+#else
+#define RANDOM_RESEED_INIT_LOCK(x) mtx_init(&yarrow_state.ys_mtx, mtx_plain)
+#define RANDOM_RESEED_DEINIT_LOCK(x) mtx_destroy(&yarrow_state.ys_mtx)
+#define RANDOM_RESEED_LOCK(x) mtx_lock(&yarrow_state.ys_mtx)
+#define RANDOM_RESEED_UNLOCK(x) mtx_unlock(&yarrow_state.ys_mtx)
+#define RANDOM_RESEED_ASSERT_LOCK_OWNED(x)
#endif
-void random_yarrow_init_alg(void);
-void random_yarrow_deinit_alg(void);
-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
+#endif /* SYS_DEV_RANDOM_YARROW_H_INCLUDED */
diff --git a/sys/dev/rndtest/rndtest.c b/sys/dev/rndtest/rndtest.c
index 871d0b7..a00cb6a 100644
--- a/sys/dev/rndtest/rndtest.c
+++ b/sys/dev/rndtest/rndtest.c
@@ -145,16 +145,9 @@ rndtest_harvest(struct rndtest_state *rsp, void *buf, u_int len)
*/
if (rsp->rs_discard)
rndstats.rst_discard += len;
- else {
-#if __FreeBSD_version < 500000
- /* XXX verify buffer is word aligned */
- u_int32_t *p = buf;
- for (len /= sizeof (u_int32_t); len; len--)
- add_true_randomness(*p++);
-#else
- random_harvest(buf, len, len*NBBY/2, RANDOM_PURE_RNDTEST);
-#endif
- }
+ else
+ /* MarkM: FIX!! Check that this does not swamp the harvester! */
+ random_harvest_queue(buf, len, len*NBBY/2, RANDOM_PURE_RNDTEST);
}
static void
diff --git a/sys/dev/safe/safe.c b/sys/dev/safe/safe.c
index 2df1f51..93714ca 100644
--- a/sys/dev/safe/safe.c
+++ b/sys/dev/safe/safe.c
@@ -211,7 +211,8 @@ safe_partname(struct safe_softc *sc)
static void
default_harvest(struct rndtest_state *rsp, void *buf, u_int count)
{
- random_harvest(buf, count, count*NBBY/2, RANDOM_PURE_SAFE);
+ /* MarkM: FIX!! Check that this does not swamp the harvester! */
+ random_harvest_queue(buf, count, count*NBBY/2, RANDOM_PURE_SAFE);
}
#endif /* SAFE_NO_RNG */
diff --git a/sys/dev/syscons/scmouse.c b/sys/dev/syscons/scmouse.c
index 4dbd1a7..5895066 100644
--- a/sys/dev/syscons/scmouse.c
+++ b/sys/dev/syscons/scmouse.c
@@ -666,7 +666,7 @@ sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
mouse = (mouse_info_t*)data;
- random_harvest(mouse, sizeof(mouse_info_t), 2, RANDOM_MOUSE);
+ random_harvest_queue(mouse, sizeof(mouse_info_t), 2, RANDOM_MOUSE);
if (cmd == OLD_CONS_MOUSECTL) {
static u_char swapb[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
diff --git a/sys/dev/syscons/syscons.c b/sys/dev/syscons/syscons.c
index 2ab2889..f109b24 100644
--- a/sys/dev/syscons/syscons.c
+++ b/sys/dev/syscons/syscons.c
@@ -3411,7 +3411,7 @@ next_code:
sc_touch_scrn_saver();
if (!(flags & SCGETC_CN))
- random_harvest(&c, sizeof(c), 1, RANDOM_KEYBOARD);
+ random_harvest_queue(&c, sizeof(c), 1, RANDOM_KEYBOARD);
if (scp->kbd_mode != K_XLATE)
return KEYCHAR(c);
diff --git a/sys/dev/ubsec/ubsec.c b/sys/dev/ubsec/ubsec.c
index 27bb591..53e3ef8 100644
--- a/sys/dev/ubsec/ubsec.c
+++ b/sys/dev/ubsec/ubsec.c
@@ -259,7 +259,8 @@ ubsec_partname(struct ubsec_softc *sc)
static void
default_harvest(struct rndtest_state *rsp, void *buf, u_int count)
{
- random_harvest(buf, count, count*NBBY/2, RANDOM_PURE_UBSEC);
+ /* MarkM: FIX!! Check that this does not swamp the harvester! */
+ random_harvest_queue(buf, count, count*NBBY/2, RANDOM_PURE_UBSEC);
}
static int
diff --git a/sys/dev/virtio/random/virtio_random.c b/sys/dev/virtio/random/virtio_random.c
index caa4288..8c08853 100644
--- a/sys/dev/virtio/random/virtio_random.c
+++ b/sys/dev/virtio/random/virtio_random.c
@@ -215,7 +215,7 @@ vtrnd_harvest(struct vtrnd_softc *sc)
virtqueue_notify(vq);
virtqueue_poll(vq, NULL);
- random_harvest(&value, sizeof(value), sizeof(value) * NBBY / 2,
+ random_harvest_queue(&value, sizeof(value), sizeof(value) * NBBY / 2,
RANDOM_PURE_VIRTIO);
}
diff --git a/sys/dev/vt/vt_core.c b/sys/dev/vt/vt_core.c
index ecd5267..907a4a1 100644
--- a/sys/dev/vt/vt_core.c
+++ b/sys/dev/vt/vt_core.c
@@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <sys/power.h>
#include <sys/priv.h>
#include <sys/proc.h>
+#include <sys/random.h>
#include <sys/reboot.h>
#include <sys/systm.h>
#include <sys/terminal.h>
@@ -732,6 +733,7 @@ vt_processkey(keyboard_t *kbd, struct vt_device *vd, int c)
{
struct vt_window *vw = vd->vd_curwindow;
+ random_harvest_queue(&c, sizeof(c), 1, RANDOM_KEYBOARD);
#if VT_ALT_TO_ESC_HACK
if (c & RELKEY) {
switch (c & ~RELKEY) {
diff --git a/sys/dev/vt/vt_sysmouse.c b/sys/dev/vt/vt_sysmouse.c
index 189bcad..618ff0f 100644
--- a/sys/dev/vt/vt_sysmouse.c
+++ b/sys/dev/vt/vt_sysmouse.c
@@ -139,7 +139,7 @@ sysmouse_process_event(mouse_info_t *mi)
unsigned char buf[MOUSE_SYS_PACKETSIZE];
int x, y, iy, z;
- random_harvest(mi, sizeof *mi, 2, RANDOM_MOUSE);
+ random_harvest_queue(mi, sizeof *mi, 2, RANDOM_MOUSE);
mtx_lock(&sysmouse_lock);
switch (mi->operation) {
OpenPOWER on IntegriCloud