From owner-svn-src-all@FreeBSD.ORG Thu Oct 30 21:21:59 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 473F786A; Thu, 30 Oct 2014 21:21:59 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 2F35460F; Thu, 30 Oct 2014 21:21:59 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id s9ULLxi8055652; Thu, 30 Oct 2014 21:21:59 GMT (envelope-from markm@FreeBSD.org) Received: (from markm@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id s9ULLsEw055630; Thu, 30 Oct 2014 21:21:54 GMT (envelope-from markm@FreeBSD.org) Message-Id: <201410302121.s9ULLsEw055630@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: markm set sender to markm@FreeBSD.org using -f From: Mark Murray Date: Thu, 30 Oct 2014 21:21:54 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: 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... X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 30 Oct 2014 21:21:59 -0000 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 #include -#include -#include #include +#include +#include +#include -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 bytes of random stuff into . You may presume + * that 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 + * 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 __FBSDID("$FreeBSD$"); +#include "opt_random.h" + #include +#include #include #include +#include #include -#include #include -#include +#include #include -#include -#include #include - -static struct mtx dummy_random_mtx; - -/* Used to fake out unused random calls in random_adaptor */ -static void -random_null_func(void) -{ -} +#include 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 +__FBSDID("$FreeBSD$"); + +#ifdef _KERNEL +#include "opt_random.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#else /* !_KERNEL */ +#include +#include +#include +#include +#include +#include +#include + +#include "unit_test.h" + +#include +#include + +#include +#include +#include +#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| */ + /* 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, ×tamp, sizeof(timestamp)); + randomdev_hash_iterate(&fortuna_start_cache.hash, buf, count); + timestamp = get_cyclecount(); + randomdev_hash_iterate(&fortuna_start_cache.hash, ×tamp, 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 __FBSDID("$FreeBSD$"); +#ifdef _KERNEL #include #include +#else /* !_KERNEL */ +#include +#include +#include +#include +#include +#include +#include +#include "unit_test.h" +#endif /* _KERNEL */ #include #include #include +/* 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 #include +#include #include #include #include #include -#include #include #include @@ -47,18 +47,17 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include #include +#include #define RETRY_COUNT 10 *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***