svn commit: r273872 - in head: etc/defaults etc/rc.d libexec/save-entropy share/examples/kld/random_adaptor sys/conf sys/dev/glxsb sys/dev/random sys/kern sys/modules sys/modules/padlock_rng sys/mo...

Mark Murray markm at FreeBSD.org
Thu Oct 30 21:21:59 UTC 2014


Author: markm
Date: Thu Oct 30 21:21:53 2014
New Revision: 273872
URL: https://svnweb.freebsd.org/changeset/base/273872

Log:
  This is the much-discussed major upgrade to the random(4) device, known to you all as /dev/random.
  
  This code has had an extensive rewrite and a good series of reviews, both by the author and other parties. This means a lot of code has been simplified. Pluggable structures for high-rate entropy generators are available, and it is most definitely not the case that /dev/random can be driven by only a hardware souce any more. This has been designed out of the device. Hardware sources are stirred into the CSPRNG (Yarrow, Fortuna) like any other entropy source. Pluggable modules may be written by third parties for additional sources.
  
  The harvesting structures and consequently the locking have been simplified. Entropy harvesting is done in a more general way (the documentation for this will follow). There is some GREAT entropy to be had in the UMA allocator, but it is disabled for now as messing with that is likely to annoy many people.
  
  The venerable (but effective) Yarrow algorithm, which is no longer supported by its authors now has an alternative, Fortuna. For now, Yarrow is retained as the default algorithm, but this may be changed using a kernel option. It is intended to make Fortuna the default algorithm for 11.0. Interested parties are encouraged to read ISBN 978-0-470-47424-2 "Cryptography Engineering" By Ferguson, Schneier and Kohno for Fortuna's gory details. Heck, read it anyway.
  
  Many thanks to Arthur Mesh who did early grunt work, and who got caught in the crossfire rather more than he deserved to.
  
  My thanks also to folks who helped me thresh this out on whiteboards and in the odd "Hallway track", or otherwise.
  
  My Nomex pants are on. Let the feedback commence!
  
  Reviewed by:	trasz,des(partial),imp(partial?),rwatson(partial?)
  Approved by:	so(des)

Added:
  head/sys/dev/random/build.sh   (contents, props changed)
  head/sys/dev/random/fortuna.c   (contents, props changed)
  head/sys/dev/random/fortuna.h   (contents, props changed)
  head/sys/dev/random/uint128.h   (contents, props changed)
  head/sys/dev/random/unit_test.c   (contents, props changed)
  head/sys/dev/random/unit_test.h   (contents, props changed)
  head/sys/modules/padlock_rng/
  head/sys/modules/padlock_rng/Makefile   (contents, props changed)
  head/sys/modules/rdrand_rng/
  head/sys/modules/rdrand_rng/Makefile   (contents, props changed)
Deleted:
  head/etc/rc.d/initrandom
  head/sys/dev/random/harvest.c
  head/sys/dev/random/rwfile.c
  head/sys/dev/random/rwfile.h
Modified:
  head/etc/defaults/rc.conf
  head/etc/rc.d/Makefile
  head/etc/rc.d/geli
  head/etc/rc.d/postrandom
  head/etc/rc.d/random
  head/libexec/save-entropy/save-entropy.sh
  head/share/examples/kld/random_adaptor/random_adaptor_example.c
  head/sys/conf/NOTES
  head/sys/conf/files
  head/sys/conf/options
  head/sys/dev/glxsb/glxsb.c
  head/sys/dev/random/dummy_rng.c
  head/sys/dev/random/hash.c
  head/sys/dev/random/hash.h
  head/sys/dev/random/ivy.c
  head/sys/dev/random/live_entropy_sources.c
  head/sys/dev/random/live_entropy_sources.h
  head/sys/dev/random/nehemiah.c
  head/sys/dev/random/random_adaptors.c
  head/sys/dev/random/random_adaptors.h
  head/sys/dev/random/random_harvestq.c
  head/sys/dev/random/random_harvestq.h
  head/sys/dev/random/randomdev.c
  head/sys/dev/random/randomdev.h
  head/sys/dev/random/randomdev_soft.c
  head/sys/dev/random/randomdev_soft.h
  head/sys/dev/random/yarrow.c
  head/sys/dev/random/yarrow.h
  head/sys/kern/init_main.c
  head/sys/kern/kern_intr.c
  head/sys/kern/subr_bus.c
  head/sys/modules/Makefile
  head/sys/modules/random/Makefile
  head/sys/net/if_ethersubr.c
  head/sys/net/if_tun.c
  head/sys/netgraph/ng_iface.c
  head/sys/sys/random.h
  head/sys/vm/uma_core.c

Modified: head/etc/defaults/rc.conf
==============================================================================
--- head/etc/defaults/rc.conf	Thu Oct 30 17:58:57 2014	(r273871)
+++ head/etc/defaults/rc.conf	Thu Oct 30 21:21:53 2014	(r273872)
@@ -645,7 +645,7 @@ update_motd="YES"	# update version info 
 entropy_file="/entropy"	# Set to NO to disable caching entropy through reboots.
 			# /var/db/entropy-file is preferred if / is not avail.
 entropy_dir="/var/db/entropy" # Set to NO to disable caching entropy via cron.
-entropy_save_sz="2048"	# Size of the entropy cache files.
+entropy_save_sz="4096"	# Size of the entropy cache files.
 entropy_save_num="8"	# Number of entropy cache files to save.
 harvest_interrupt="YES"	# Entropy device harvests interrupt randomness
 harvest_ethernet="YES"	# Entropy device harvests ethernet randomness

Modified: head/etc/rc.d/Makefile
==============================================================================
--- head/etc/rc.d/Makefile	Thu Oct 30 17:58:57 2014	(r273871)
+++ head/etc/rc.d/Makefile	Thu Oct 30 21:21:53 2014	(r273872)
@@ -57,7 +57,6 @@ FILES=	DAEMON \
 	hostid_save \
 	hostname \
 	inetd \
-	initrandom \
 	ip6addrctl \
 	ipfilter \
 	ipfs \

Modified: head/etc/rc.d/geli
==============================================================================
--- head/etc/rc.d/geli	Thu Oct 30 17:58:57 2014	(r273871)
+++ head/etc/rc.d/geli	Thu Oct 30 21:21:53 2014	(r273872)
@@ -28,7 +28,7 @@
 #
 
 # PROVIDE: disks
-# REQUIRE: initrandom
+# REQUIRE: random
 # KEYWORD: nojail
 
 . /etc/rc.subr

Modified: head/etc/rc.d/postrandom
==============================================================================
--- head/etc/rc.d/postrandom	Thu Oct 30 17:58:57 2014	(r273871)
+++ head/etc/rc.d/postrandom	Thu Oct 30 21:21:53 2014	(r273872)
@@ -4,7 +4,7 @@
 #
 
 # PROVIDE: postrandom
-# REQUIRE: initrandom random FILESYSTEMS
+# REQUIRE: random FILESYSTEMS
 # BEFORE: LOGIN
 # KEYWORD: nojail
 

Modified: head/etc/rc.d/random
==============================================================================
--- head/etc/rc.d/random	Thu Oct 30 17:58:57 2014	(r273871)
+++ head/etc/rc.d/random	Thu Oct 30 21:21:53 2014	(r273872)
@@ -4,7 +4,7 @@
 #
 
 # PROVIDE: random
-# REQUIRE: initrandom FILESYSTEMS
+# REQUIRE: FILESYSTEMS
 # BEFORE: netif
 # KEYWORD: nojail shutdown
 

Modified: head/libexec/save-entropy/save-entropy.sh
==============================================================================
--- head/libexec/save-entropy/save-entropy.sh	Thu Oct 30 17:58:57 2014	(r273871)
+++ head/libexec/save-entropy/save-entropy.sh	Thu Oct 30 21:21:53 2014	(r273872)
@@ -53,7 +53,7 @@ case ${entropy_dir} in
 	;;
 esac
 
-entropy_save_sz=${entropy_save_sz:-2048}
+entropy_save_sz=${entropy_save_sz:-4096}
 entropy_save_num=${entropy_save_num:-8}
 
 if [ ! -d "${entropy_dir}" ]; then

Modified: head/share/examples/kld/random_adaptor/random_adaptor_example.c
==============================================================================
--- head/share/examples/kld/random_adaptor/random_adaptor_example.c	Thu Oct 30 17:58:57 2014	(r273871)
+++ head/share/examples/kld/random_adaptor/random_adaptor_example.c	Thu Oct 30 21:21:53 2014	(r273872)
@@ -35,17 +35,20 @@ __FBSDID("$FreeBSD$");
 #include <sys/random.h>
 #include <sys/systm.h>
 
-#include <dev/random/live_entropy_sources.h>
-#include <dev/random/random_adaptors.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 int random_example_read(void *, int);
-
-struct random_adaptor random_example = {
-	.ident = "Example RNG",
-	.source = RANDOM_PURE_BOGUS,	/* Make sure this is in
-					 * sys/random.h and is unique */
-	.read = random_example_read,
+static void live_random_example_init(void);
+static void live_random_example_deinit(void);
+static u_int live_random_example_read(void *, u_int);
+
+struct random_adaptor live_random_example = {
+	.les_ident = "Example RNG",
+	.les_source = RANDOM_PURE_BOGUS, /* Make sure this is in
+					  * sys/random.h and is unique */
+	.les_read = live_random_example_read,
 };
 
 /*
@@ -58,8 +61,26 @@ getRandomNumber(void)
 	return 4;   /* chosen by fair dice roll, guaranteed to be random */
 }
 
-static int
-random_example_read(void *buf, int c)
+static void
+live_random_example_init(void)
+{
+
+	/* Do initialisation stuff here */
+}
+
+static void
+live_random_example_deinit(void)
+{
+
+	/* Do de-initialisation stuff here */
+}
+
+/* get <c> bytes of random stuff into <buf>. You may presume
+ * that <c> is a multiple of 2^n, with n>=3. A typical value
+ * is c=16.
+ */
+static u_int
+live_random_example_read(void *buf, u_int c)
 {
 	uint8_t *b;
 	int count;
@@ -69,22 +90,23 @@ random_example_read(void *buf, int c)
 	for (count = 0; count < c; count++)
 		b[count] = getRandomNumber();
 
-	printf("returning %d bytes of pure randomness\n", c);
+	/* printf("returning %d bytes of pure randomness\n", c); */
 	return (c);
 }
 
+/* ARGSUSED */
 static int
-random_example_modevent(module_t mod, int type, void *unused)
+live_random_example_modevent(module_t mod __unused, int type, void *unused __unused)
 {
 	int error = 0;
 
 	switch (type) {
 	case MOD_LOAD:
-		live_entropy_source_register(&random_example);
+		live_entropy_source_register(&live_random_example);
 		break;
 
 	case MOD_UNLOAD:
-		live_entropy_source_deregister(&random_example);
+		live_entropy_source_deregister(&live_random_example);
 		break;
 
 	case MOD_SHUTDOWN:
@@ -98,4 +120,6 @@ random_example_modevent(module_t mod, in
 	return (error);
 }
 
-LIVE_ENTROPY_SRC_MODULE(live_entropy_source_example, random_example_modevent, 1);
+DEV_MODULE(live_random_example, live_random_example_modevent, NULL);
+MODULE_VERSION(live_random_example, 1);
+MODULE_DEPEND(live_random_example, randomdev, 1, 1, 1);

Modified: head/sys/conf/NOTES
==============================================================================
--- head/sys/conf/NOTES	Thu Oct 30 17:58:57 2014	(r273871)
+++ head/sys/conf/NOTES	Thu Oct 30 21:21:53 2014	(r273872)
@@ -2993,10 +2993,10 @@ options 	BROOKTREE_ALLOC_PAGES=(217*4+1)
 options 	MAXFILES=999
 
 # Random number generator
-options 	RANDOM_YARROW	# Yarrow RNG
-##options 	RANDOM_FORTUNA	# Fortuna RNG - not yet implemented
+# Only ONE of the below two may be used; they are mutually exclusive.
+options 	RANDOM_YARROW	# Yarrow CSPRNG (Default)
+#options 	RANDOM_FORTUNA	# Fortuna CSPRNG
 options 	RANDOM_DEBUG	# Debugging messages
-options 	RANDOM_RWFILE	# Read and write entropy cache
 
 # Module to enable execution of application via emulators like QEMU
 options         IMAGACT_BINMISC

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Thu Oct 30 17:58:57 2014	(r273871)
+++ head/sys/conf/files	Thu Oct 30 21:21:53 2014	(r273872)
@@ -2132,16 +2132,15 @@ rt2860.fw			optional rt2860fw | ralfw		\
 	compile-with	"${NORMAL_FW}"					\
 	no-obj no-implicit-rule						\
 	clean		"rt2860.fw"
-dev/random/harvest.c		standard
-dev/random/dummy_rng.c		standard
+dev/random/randomdev.c		standard
 dev/random/random_adaptors.c	standard
-dev/random/live_entropy_sources.c	optional random
-dev/random/random_harvestq.c	optional random
-dev/random/randomdev.c		optional random
+dev/random/dummy_rng.c		standard
+dev/random/live_entropy_sources.c	standard
+dev/random/random_harvestq.c	standard
 dev/random/randomdev_soft.c	optional random
 dev/random/yarrow.c		optional random
+dev/random/fortuna.c		optional random
 dev/random/hash.c		optional random
-dev/random/rwfile.c		optional random
 dev/rc/rc.c			optional rc
 dev/re/if_re.c			optional re
 dev/rl/if_rl.c			optional rl pci

Modified: head/sys/conf/options
==============================================================================
--- head/sys/conf/options	Thu Oct 30 17:58:57 2014	(r273871)
+++ head/sys/conf/options	Thu Oct 30 21:21:53 2014	(r273872)
@@ -930,4 +930,3 @@ RCTL		opt_global.h
 RANDOM_YARROW	opt_random.h
 RANDOM_FORTUNA	opt_random.h
 RANDOM_DEBUG	opt_random.h
-RANDOM_RWFILE	opt_random.h

Modified: head/sys/dev/glxsb/glxsb.c
==============================================================================
--- head/sys/dev/glxsb/glxsb.c	Thu Oct 30 17:58:57 2014	(r273871)
+++ head/sys/dev/glxsb/glxsb.c	Thu Oct 30 21:21:53 2014	(r273872)
@@ -476,7 +476,7 @@ 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, 4, 32/2, RANDOM_PURE_GLXSB);
+		random_harvest(&value, sizeof(value), 32/2, RANDOM_PURE_GLXSB);
 	}
 
 	callout_reset(&sc->sc_rngco, sc->sc_rnghz, glxsb_rnd, sc);

Added: head/sys/dev/random/build.sh
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/random/build.sh	Thu Oct 30 21:21:53 2014	(r273872)
@@ -0,0 +1,24 @@
+# $FreeBSD$
+#
+# Basic script to build crude unit tests.
+#
+cc -g -O0 -pthread -DRANDOM_DEBUG -DRANDOM_YARROW \
+	-I../.. -lstdthreads -Wall \
+	unit_test.c \
+	yarrow.c \
+	hash.c \
+	../../crypto/rijndael/rijndael-api-fst.c \
+	../../crypto/rijndael/rijndael-alg-fst.c \
+	../../crypto/sha2/sha2.c \
+	../../crypto/sha2/sha256c.c \
+	-o yunit_test
+cc -g -O0 -pthread -DRANDOM_DEBUG -DRANDOM_FORTUNA \
+	-I../.. -lstdthreads -Wall \
+	unit_test.c \
+	fortuna.c \
+	hash.c \
+	../../crypto/rijndael/rijndael-api-fst.c \
+	../../crypto/rijndael/rijndael-alg-fst.c \
+	../../crypto/sha2/sha2.c \
+	../../crypto/sha2/sha256c.c \
+	-o funit_test

Modified: head/sys/dev/random/dummy_rng.c
==============================================================================
--- head/sys/dev/random/dummy_rng.c	Thu Oct 30 17:58:57 2014	(r273871)
+++ head/sys/dev/random/dummy_rng.c	Thu Oct 30 21:21:53 2014	(r273872)
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 2013 Arthur Mesh <arthurmesh at gmail.com>
+ * Copyright (c) 2013 Mark R V Murray
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -27,98 +28,92 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include "opt_random.h"
+
 #include <sys/param.h>
+#include <sys/conf.h>
 #include <sys/fcntl.h>
 #include <sys/kernel.h>
+#include <sys/lock.h>
 #include <sys/malloc.h>
-#include <sys/module.h>
 #include <sys/random.h>
-#include <sys/selinfo.h>
+#include <sys/syslog.h>
 #include <sys/systm.h>
-#include <sys/time.h>
 
-#include <dev/random/random_adaptors.h>
 #include <dev/random/randomdev.h>
-
-static struct mtx	dummy_random_mtx;
-
-/* Used to fake out unused random calls in random_adaptor */
-static void
-random_null_func(void)
-{
-}
+#include <dev/random/random_adaptors.h>
 
 static int
-dummy_random_poll(int events __unused, struct thread *td __unused)
+dummy_random_zero(void)
 {
 
 	return (0);
 }
 
-static int
-dummy_random_block(int flag)
+static void
+dummy_random(void)
 {
-	int error = 0;
-
-	mtx_lock(&dummy_random_mtx);
-
-	/* Blocking logic */
-	while (!error) {
-		if (flag & O_NONBLOCK)
-			error = EWOULDBLOCK;
-		else {
-			printf("random: dummy device blocking on read.\n");
-			error = msleep(&dummy_random_block,
-			    &dummy_random_mtx,
-			    PUSER | PCATCH, "block", 0);
-		}
-	}
-	mtx_unlock(&dummy_random_mtx);
-
-	return (error);
 }
 
+/* ARGSUSED */
 static void
 dummy_random_init(void)
 {
 
-	mtx_init(&dummy_random_mtx, "sleep mtx for dummy_random",
-	    NULL, MTX_DEF);
-}
-
-static void
-dummy_random_deinit(void)
-{
+#ifdef RANDOM_DEBUG
+	printf("random: %s\n", __func__);
+#endif
 
-	mtx_destroy(&dummy_random_mtx);
+	randomdev_init_reader(dummy_random_read_phony);
 }
 
-struct random_adaptor dummy_random = {
-	.ident = "Dummy entropy device that always blocks",
-	.init = dummy_random_init,
-	.deinit = dummy_random_deinit,
-	.block = dummy_random_block,
-	.poll = dummy_random_poll,
-	.read = (random_read_func_t *)random_null_func,
-	.reseed = (random_reseed_func_t *)random_null_func,
-	.seeded = 0, /* This device can never be seeded */
-	.priority = 1, /* Bottom priority, so goes to last position */
-};
-
-static int
-dummy_random_modevent(module_t mod __unused, int type, void *unused __unused)
+/* This is used only by the internal read_random(9) call, and then only
+ * if no entropy processor is loaded.
+ *
+ * Make a token effort to provide _some_ kind of output. No warranty of
+ * the quality of this output is made, mainly because its lousy.
+ *
+ * This is only used by the internal read_random(9) call when no other
+ * adaptor is active.
+ *
+ * It has external scope due to the way things work in
+ * randomdev_[de]init_reader() that the rest of the world doesn't need to
+ * know about.
+ *
+ * Caveat Emptor.
+ */
+u_int
+dummy_random_read_phony(uint8_t *buf, u_int count)
 {
+	/* If no entropy device is loaded, don't spam the console with warnings */
+	static int warned = 0;
+	u_long randval;
+	size_t size, i;
+
+	if (!warned) {
+		log(LOG_WARNING, "random device not loaded/active; using insecure pseudo-random number generator\n");
+		warned = 1;
+	}
 
-	switch (type) {
-	case MOD_LOAD:
-		random_adaptor_register("dummy", &dummy_random);
-		EVENTHANDLER_INVOKE(random_adaptor_attach,
-		    &dummy_random);
+	/* srandom() is called in kern/init_main.c:proc0_post() */
 
-		return (0);
+	/* Fill buf[] with random(9) output */
+	for (i = 0; i < count; i += sizeof(randval)) {
+		randval = random();
+		size = MIN(count - i, sizeof(randval));
+		memcpy(buf + i, &randval, (size_t)size);
 	}
 
-	return (EINVAL);
+	return (count);
 }
 
-RANDOM_ADAPTOR_MODULE(dummy, dummy_random_modevent, 1);
+struct random_adaptor randomdev_dummy = {
+	.ra_ident = "Dummy",
+	.ra_priority = 1, /* Bottom priority, so goes to last position */
+	.ra_reseed = dummy_random,
+	.ra_seeded = (random_adaptor_seeded_func_t *)dummy_random_zero,
+	.ra_read = (random_adaptor_read_func_t *)dummy_random_zero,
+	.ra_write = (random_adaptor_write_func_t *)dummy_random_zero,
+	.ra_init = dummy_random_init,
+	.ra_deinit = dummy_random,
+};

Added: head/sys/dev/random/fortuna.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/random/fortuna.c	Thu Oct 30 21:21:53 2014	(r273872)
@@ -0,0 +1,433 @@
+/*-
+ * Copyright (c) 2013-2014 Mark R V Murray
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef _KERNEL
+#include "opt_random.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/random.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+
+#include <machine/cpu.h>
+
+#include <crypto/rijndael/rijndael-api-fst.h>
+#include <crypto/sha2/sha2.h>
+
+#include <dev/random/hash.h>
+#include <dev/random/randomdev.h>
+#include <dev/random/random_adaptors.h>
+#include <dev/random/random_harvestq.h>
+#include <dev/random/uint128.h>
+#include <dev/random/fortuna.h>
+#else /* !_KERNEL */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <threads.h>
+
+#include "unit_test.h"
+
+#include <crypto/rijndael/rijndael-api-fst.h>
+#include <crypto/sha2/sha2.h>
+
+#include <dev/random/hash.h>
+#include <dev/random/uint128.h>
+#include <dev/random/fortuna.h>
+#endif /* _KERNEL */
+
+#if !defined(RANDOM_YARROW) && !defined(RANDOM_FORTUNA)
+#define RANDOM_YARROW
+#elif defined(RANDOM_YARROW) && defined(RANDOM_FORTUNA)
+#error "Must define either RANDOM_YARROW or RANDOM_FORTUNA"
+#endif
+
+#if defined(RANDOM_FORTUNA)
+
+#define NPOOLS 32
+#define MINPOOLSIZE 64
+#define DEFPOOLSIZE 256
+#define MAXPOOLSIZE 65536
+
+/* This algorithm (and code) presumes that KEYSIZE is twice as large as BLOCKSIZE */
+CTASSERT(BLOCKSIZE == sizeof(uint128_t));
+CTASSERT(KEYSIZE == 2*BLOCKSIZE);
+
+/* This is the beastie that needs protecting. It contains all of the
+ * state that we are excited about.
+ * Exactly one is instantiated.
+ */
+static struct fortuna_state {
+	/* P_i */
+	struct pool {
+		u_int length;
+		struct randomdev_hash hash;
+	} pool[NPOOLS];
+
+	/* ReseedCnt */
+	u_int reseedcount;
+
+	/* C - 128 bits */
+	union {
+		uint8_t byte[BLOCKSIZE];
+		uint128_t whole;
+	} counter;
+
+	/* K */
+	struct randomdev_key key;
+
+	/* Extras */
+	u_int minpoolsize;
+
+	/* Extras for the OS */
+
+#ifdef _KERNEL
+	/* For use when 'pacing' the reseeds */
+	sbintime_t lasttime;
+#endif
+} fortuna_state;
+
+/* The random_reseed_mtx mutex protects seeding and polling/blocking.  */
+static mtx_t random_reseed_mtx;
+
+static struct fortuna_start_cache {
+	uint8_t junk[PAGE_SIZE];
+	size_t length;
+	struct randomdev_hash hash;
+} fortuna_start_cache;
+
+#ifdef _KERNEL
+static struct sysctl_ctx_list random_clist;
+RANDOM_CHECK_UINT(minpoolsize, MINPOOLSIZE, MAXPOOLSIZE);
+#endif
+
+void
+random_fortuna_init_alg(void)
+{
+	int i;
+#ifdef _KERNEL
+	struct sysctl_oid *random_fortuna_o;
+#endif
+
+	memset(fortuna_start_cache.junk, 0, sizeof(fortuna_start_cache.junk));
+	fortuna_start_cache.length = 0U;
+	randomdev_hash_init(&fortuna_start_cache.hash);
+
+	/* Set up a lock for the reseed process */
+#ifdef _KERNEL
+	mtx_init(&random_reseed_mtx, "reseed mutex", NULL, MTX_DEF);
+#else /* !_KERNEL */
+	mtx_init(&random_reseed_mtx, mtx_plain);
+#endif /* _KERNEL */
+
+#ifdef _KERNEL
+	/* Fortuna parameters. Do not adjust these unless you have
+	 * have a very good clue about what they do!
+	 */
+	random_fortuna_o = SYSCTL_ADD_NODE(&random_clist,
+		SYSCTL_STATIC_CHILDREN(_kern_random),
+		OID_AUTO, "fortuna", CTLFLAG_RW, 0,
+		"Fortuna Parameters");
+
+	SYSCTL_ADD_PROC(&random_clist,
+		SYSCTL_CHILDREN(random_fortuna_o), OID_AUTO,
+		"minpoolsize", CTLTYPE_UINT|CTLFLAG_RW,
+		&fortuna_state.minpoolsize, DEFPOOLSIZE,
+		random_check_uint_minpoolsize, "IU",
+		"Minimum pool size necessary to cause a reseed automatically");
+
+	fortuna_state.lasttime = 0U;
+#endif
+
+	fortuna_state.minpoolsize = DEFPOOLSIZE;
+
+	/* F&S - InitializePRNG() */
+
+	/* F&S - P_i = \epsilon */
+	for (i = 0; i < NPOOLS; i++) {
+		randomdev_hash_init(&fortuna_state.pool[i].hash);
+		fortuna_state.pool[i].length = 0U;
+	}
+
+	/* F&S - ReseedCNT = 0 */
+	fortuna_state.reseedcount = 0U;
+
+	/* F&S - InitializeGenerator() */
+
+	/* F&S - C = 0 */
+	uint128_clear(&fortuna_state.counter.whole);
+
+	/* F&S - K = 0 */
+	memset(&fortuna_state.key, 0, sizeof(fortuna_state.key));
+}
+
+void
+random_fortuna_deinit_alg(void)
+{
+
+	mtx_destroy(&random_reseed_mtx);
+	memset(&fortuna_state, 0, sizeof(fortuna_state));
+}
+
+/* F&S - AddRandomEvent() */
+/* Process a single stochastic event off the harvest queue */
+void
+random_fortuna_process_event(struct harvest_event *event)
+{
+	u_int pl;
+
+	/* We must be locked for all this as plenty of state gets messed with */
+	mtx_lock(&random_reseed_mtx);
+
+	/* Accumulate the event into the appropriate pool
+	 * where each event carries the destination information
+	 */
+	/* F&S - P_i = P_i|<harvested stuff> */
+	/* The hash_init and hash_finish are done in random_fortuna_read() below */
+	pl = event->he_destination % NPOOLS;
+	randomdev_hash_iterate(&fortuna_state.pool[pl].hash, event, sizeof(*event));
+	/* No point in counting above the outside maximum */
+	fortuna_state.pool[pl].length += event->he_size;
+	fortuna_state.pool[pl].length = MIN(fortuna_state.pool[pl].length, MAXPOOLSIZE);
+
+	/* Done with state-messing */
+	mtx_unlock(&random_reseed_mtx);
+}
+
+/* F&S - Reseed() */
+/* Reseed Mutex is held */
+static void
+reseed(uint8_t *junk, u_int length)
+{
+	struct randomdev_hash context;
+	uint8_t hash[KEYSIZE], temp[KEYSIZE];
+
+	KASSERT(fortuna_state.minpoolsize > 0, ("random: Fortuna threshold = 0"));
+#ifdef _KERNEL
+	mtx_assert(&random_reseed_mtx, MA_OWNED);
+#endif
+
+	/* F&S - temp = H(K|s) */
+	randomdev_hash_init(&context);
+	randomdev_hash_iterate(&context, &fortuna_state.key, sizeof(fortuna_state.key));
+	randomdev_hash_iterate(&context, junk, length);
+	randomdev_hash_finish(&context, temp);
+
+	/* F&S - hash = H(temp) */
+	randomdev_hash_init(&context);
+	randomdev_hash_iterate(&context, temp, KEYSIZE);
+	randomdev_hash_finish(&context, hash);
+
+	/* F&S - K = hash */
+	randomdev_encrypt_init(&fortuna_state.key, temp);
+	memset(temp, 0, sizeof(temp));
+	memset(hash, 0, sizeof(hash));
+
+	/* Unblock the device if it was blocked due to being unseeded */
+	if (uint128_is_zero(fortuna_state.counter.whole))
+		random_adaptor_unblock();
+	/* F&S - C = C + 1 */
+	uint128_increment(&fortuna_state.counter.whole);
+}
+
+/* F&S - GenerateBlocks() */
+/* Reseed Mutex is held, and buf points to a whole number of blocks. */
+static __inline void
+random_fortuna_genblocks(uint8_t *buf, u_int blockcount)
+{
+	u_int i;
+
+	for (i = 0u; i < blockcount; i++) {
+		/* F&S - r = r|E(K,C) */
+		randomdev_encrypt(&fortuna_state.key, fortuna_state.counter.byte, buf, BLOCKSIZE);
+		buf += BLOCKSIZE;
+
+		/* F&S - C = C + 1 */
+		uint128_increment(&fortuna_state.counter.whole);
+	}
+}
+
+/* F&S - PseudoRandomData() */
+/* Reseed Mutex is held, and buf points to a whole number of blocks. */
+static __inline void
+random_fortuna_genrandom(uint8_t *buf, u_int bytecount)
+{
+	static uint8_t temp[BLOCKSIZE*(KEYSIZE/BLOCKSIZE)];
+	u_int blockcount;
+
+	/* F&S - assert(n < 2^20) */
+	KASSERT((bytecount <= (1 << 20)), ("invalid single read request to fortuna of %d bytes", bytecount));
+
+	/* F&S - r = first-n-bytes(GenerateBlocks(ceil(n/16))) */
+	blockcount = (bytecount + BLOCKSIZE - 1)/BLOCKSIZE;
+	random_fortuna_genblocks(buf, blockcount);
+
+	/* F&S - K = GenerateBlocks(2) */
+	random_fortuna_genblocks(temp, KEYSIZE/BLOCKSIZE);
+	randomdev_encrypt_init(&fortuna_state.key, temp);
+	memset(temp, 0, sizeof(temp));
+}
+
+/* F&S - RandomData() */
+/* Used to return processed entropy from the PRNG */
+/* The argument buf points to a whole number of blocks. */
+void
+random_fortuna_read(uint8_t *buf, u_int bytecount)
+{
+#ifdef _KERNEL
+	sbintime_t thistime;
+#endif
+	struct randomdev_hash context;
+	uint8_t s[NPOOLS*KEYSIZE], temp[KEYSIZE];
+	int i;
+	u_int seedlength;
+
+	/* We must be locked for all this as plenty of state gets messed with */
+	mtx_lock(&random_reseed_mtx);
+
+	/* if buf == NULL and bytecount == 0 then this is the pre-read. */
+	/* if buf == NULL and bytecount != 0 then this is the post-read; ignore. */
+	if (buf == NULL) {
+		if (bytecount == 0) {
+			if (fortuna_state.pool[0].length >= fortuna_state.minpoolsize
+#ifdef _KERNEL
+			/* F&S - Use 'getsbinuptime()' to prevent reseed-spamming. */
+		    	&& ((thistime = getsbinuptime()) - fortuna_state.lasttime > hz/10)
+#endif
+		    	) {
+#ifdef _KERNEL
+				fortuna_state.lasttime = thistime;
+#endif
+
+				seedlength = 0U;
+				/* F&S - ReseedCNT = ReseedCNT + 1 */
+				fortuna_state.reseedcount++;
+				/* s = \epsilon by default */
+				for (i = 0; i < NPOOLS; i++) {
+					/* F&S - if Divides(ReseedCnt, 2^i) ... */
+					if ((fortuna_state.reseedcount % (1 << i)) == 0U) {
+						seedlength += KEYSIZE;
+						/* F&S - temp = (P_i) */
+						randomdev_hash_finish(&fortuna_state.pool[i].hash, temp);
+						/* F&S - P_i = \epsilon */
+						randomdev_hash_init(&fortuna_state.pool[i].hash);
+						fortuna_state.pool[i].length = 0U;
+						/* F&S - s = s|H(temp) */
+						randomdev_hash_init(&context);
+						randomdev_hash_iterate(&context, temp, KEYSIZE);
+						randomdev_hash_finish(&context, s + i*KEYSIZE);
+					}
+					else
+						break;
+				}
+#ifdef RANDOM_DEBUG
+				printf("random: active reseed: reseedcount [%d] ", fortuna_state.reseedcount);
+				for (i = 0; i < NPOOLS; i++)
+					printf(" %d", fortuna_state.pool[i].length);
+				printf("\n");
+#endif
+				/* F&S */
+				reseed(s, seedlength);
+
+				/* Clean up */
+				memset(s, 0, seedlength);
+				seedlength = 0U;
+				memset(temp, 0, sizeof(temp));
+				memset(&context, 0, sizeof(context));
+			}
+		}
+	}
+	/* if buf != NULL do a regular read. */
+	else
+		random_fortuna_genrandom(buf, bytecount);
+
+	mtx_unlock(&random_reseed_mtx);
+}
+
+/* Internal function to hand external entropy to the PRNG */
+void
+random_fortuna_write(uint8_t *buf, u_int count)
+{
+	uint8_t temp[KEYSIZE];
+	int i;
+	uintmax_t timestamp;
+
+	timestamp = get_cyclecount();
+	randomdev_hash_iterate(&fortuna_start_cache.hash, &timestamp, sizeof(timestamp));
+	randomdev_hash_iterate(&fortuna_start_cache.hash, buf, count);
+	timestamp = get_cyclecount();
+	randomdev_hash_iterate(&fortuna_start_cache.hash, &timestamp, sizeof(timestamp));
+	randomdev_hash_finish(&fortuna_start_cache.hash, temp);
+	for (i = 0; i < KEYSIZE; i++)
+		fortuna_start_cache.junk[(fortuna_start_cache.length + i)%PAGE_SIZE] ^= temp[i];
+	fortuna_start_cache.length += KEYSIZE;
+
+#ifdef RANDOM_DEBUG
+	printf("random: %s - ", __func__);
+	for (i = 0; i < KEYSIZE; i++)
+		printf("%02X", temp[i]);
+	printf("\n");
+#endif
+
+	memset(temp, 0, KEYSIZE);
+
+	/* We must be locked for all this as plenty of state gets messed with */
+	mtx_lock(&random_reseed_mtx);
+
+	randomdev_hash_init(&fortuna_start_cache.hash);
+
+	reseed(fortuna_start_cache.junk, MIN(PAGE_SIZE, fortuna_start_cache.length));
+	memset(fortuna_start_cache.junk, 0, sizeof(fortuna_start_cache.junk));
+
+	mtx_unlock(&random_reseed_mtx);
+}
+
+void
+random_fortuna_reseed(void)
+{
+
+	/* CWOT */
+}
+
+int
+random_fortuna_seeded(void)
+{
+
+	return (!uint128_is_zero(fortuna_state.counter.whole));
+}
+
+#endif /* RANDOM_FORTUNA */

Added: head/sys/dev/random/fortuna.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/random/fortuna.h	Thu Oct 30 21:21:53 2014	(r273872)
@@ -0,0 +1,44 @@
+/*-
+ * 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_FORTUNA_H_INCLUDED
+#define SYS_DEV_RANDOM_FORTUNA_H_INCLUDED
+
+#ifdef _KERNEL
+typedef struct mtx mtx_t;
+#endif
+
+void random_fortuna_init_alg(void);
+void random_fortuna_deinit_alg(void);
+void random_fortuna_read(uint8_t *, u_int);
+void random_fortuna_write(uint8_t *, u_int);
+void random_fortuna_reseed(void);
+int random_fortuna_seeded(void);
+void random_fortuna_process_event(struct harvest_event *event);
+
+#endif

Modified: head/sys/dev/random/hash.c
==============================================================================
--- head/sys/dev/random/hash.c	Thu Oct 30 17:58:57 2014	(r273871)
+++ head/sys/dev/random/hash.c	Thu Oct 30 21:21:53 2014	(r273872)
@@ -28,18 +28,33 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#ifdef _KERNEL
 #include <sys/param.h>
 #include <sys/systm.h>
+#else /* !_KERNEL */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <threads.h>
+#include "unit_test.h"
+#endif /* _KERNEL */
 
 #include <crypto/rijndael/rijndael-api-fst.h>
 #include <crypto/sha2/sha2.h>
 
 #include <dev/random/hash.h>
 
+/* This code presumes that KEYSIZE is twice as large as BLOCKSIZE */
+CTASSERT(KEYSIZE == 2*BLOCKSIZE);
+
 /* Initialise the hash */
 void
 randomdev_hash_init(struct randomdev_hash *context)
 {
+
 	SHA256_Init(&context->sha);
 }
 
@@ -47,6 +62,7 @@ randomdev_hash_init(struct randomdev_has
 void
 randomdev_hash_iterate(struct randomdev_hash *context, void *data, size_t size)
 {
+
 	SHA256_Update(&context->sha, data, size);
 }
 
@@ -56,6 +72,7 @@ randomdev_hash_iterate(struct randomdev_
 void
 randomdev_hash_finish(struct randomdev_hash *context, void *buf)
 {
+
 	SHA256_Final(buf, &context->sha);
 }
 
@@ -66,6 +83,7 @@ randomdev_hash_finish(struct randomdev_h
 void
 randomdev_encrypt_init(struct randomdev_key *context, void *data)
 {
+
 	rijndael_cipherInit(&context->cipher, MODE_CBC, NULL);
 	rijndael_makeKey(&context->key, DIR_ENCRYPT, KEYSIZE*8, data);
 }
@@ -75,7 +93,8 @@ randomdev_encrypt_init(struct randomdev_
  * a multiple of BLOCKSIZE.
  */
 void
-randomdev_encrypt(struct randomdev_key *context, void *d_in, void *d_out, unsigned length)
+randomdev_encrypt(struct randomdev_key *context, void *d_in, void *d_out, u_int length)
 {
+
 	rijndael_blockEncrypt(&context->cipher, &context->key, d_in, length*8, d_out);
 }

Modified: head/sys/dev/random/hash.h
==============================================================================
--- head/sys/dev/random/hash.h	Thu Oct 30 17:58:57 2014	(r273871)
+++ head/sys/dev/random/hash.h	Thu Oct 30 21:21:53 2014	(r273872)
@@ -45,6 +45,6 @@ void randomdev_hash_init(struct randomde
 void randomdev_hash_iterate(struct randomdev_hash *, void *, size_t);
 void randomdev_hash_finish(struct randomdev_hash *, void *);
 void randomdev_encrypt_init(struct randomdev_key *, void *);
-void randomdev_encrypt(struct randomdev_key *context, void *, void *, unsigned);
+void randomdev_encrypt(struct randomdev_key *context, void *, void *, u_int);
 
 #endif

Modified: head/sys/dev/random/ivy.c
==============================================================================
--- head/sys/dev/random/ivy.c	Thu Oct 30 17:58:57 2014	(r273871)
+++ head/sys/dev/random/ivy.c	Thu Oct 30 21:21:53 2014	(r273872)
@@ -35,11 +35,11 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
+#include <sys/conf.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
 #include <sys/random.h>
-#include <sys/selinfo.h>
 #include <sys/systm.h>
 
 #include <machine/md_var.h>
@@ -47,18 +47,17 @@ __FBSDID("$FreeBSD$");
 
 #include <dev/random/randomdev.h>
 #include <dev/random/randomdev_soft.h>
-#include <dev/random/random_harvestq.h>
-#include <dev/random/live_entropy_sources.h>
 #include <dev/random/random_adaptors.h>
+#include <dev/random/live_entropy_sources.h>
 
 #define	RETRY_COUNT	10

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list