Index: sys/dev/random/build.sh =================================================================== --- sys/dev/random/build.sh +++ 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 @@ ../../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 @@ ../../crypto/rijndael/rijndael-alg-fst.c \ ../../crypto/sha2/sha2.c \ ../../crypto/sha2/sha256c.c \ + -lz \ -o funit_test Index: sys/dev/random/dummy_rng.c =================================================================== --- sys/dev/random/dummy_rng.c +++ sys/dev/random/dummy_rng.c @@ -1,6 +1,6 @@ /*- * Copyright (c) 2013 Arthur Mesh - * 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 Index: sys/dev/random/fortuna.h =================================================================== --- sys/dev/random/fortuna.h +++ 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 @@ -35,10 +35,12 @@ void random_fortuna_init_alg(void); void random_fortuna_deinit_alg(void); +void random_fortuna_pre_read(void); void random_fortuna_read(uint8_t *, u_int); +void random_fortuna_post_read(void); 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 */ Index: sys/dev/random/fortuna.c =================================================================== --- sys/dev/random/fortuna.c +++ 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 @@ -30,7 +30,7 @@ * ("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 + * Engineering" by Ferguson, Schneier and Kohno ("FS&K"). This code has * not yet fully caught up with FS&K. */ @@ -42,6 +42,7 @@ #include #include +#include #include #include #include @@ -63,6 +64,7 @@ #else /* !_KERNEL */ #include #include +#include #include #include #include @@ -90,7 +92,7 @@ #define NPOOLS 32 #define MINPOOLSIZE 64 #define DEFPOOLSIZE 256 -#define MAXPOOLSIZE 65536 +#define MAXPOOLSIZE UINT_MAX /* This algorithm (and code) presumes that KEYSIZE is twice as large as BLOCKSIZE */ CTASSERT(BLOCKSIZE == sizeof(uint128_t)); @@ -110,11 +112,8 @@ /* ReseedCnt */ u_int reseedcount; - /* C - 128 bits */ - union { - uint8_t byte[BLOCKSIZE]; - uint128_t whole; - } counter; + /* C */ + uint128_t counter; /* K */ struct randomdev_key key; @@ -123,7 +122,6 @@ u_int minpoolsize; /* Extras for the OS */ - #ifdef _KERNEL /* For use when 'pacing' the reseeds */ sbintime_t lasttime; @@ -133,15 +131,11 @@ /* 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); +#else +static uint8_t zero_region[512/8]; #endif void @@ -152,10 +146,6 @@ 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); @@ -198,7 +188,7 @@ /* F&S - InitializeGenerator() */ /* F&S - C = 0 */ - uint128_clear(&fortuna_state.counter.whole); + fortuna_state.counter = UINT128_ZERO; /* F&S - K = 0 */ memset(&fortuna_state.key, 0, sizeof(fortuna_state.key)); @@ -222,18 +212,87 @@ /* 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| + * 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. */ - /* 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); + /* Don't wrap the length. Doing the the hard way so as not to wrap at MAXUINT. + * XXX: FIX!!: We don't actually need lengths for anything but pool[0], + * but it's been useful debugging to see them all. + */ + fortuna_state.pool[pl].length = + (MAXPOOLSIZE - fortuna_state.pool[pl].length) > event->he_size + ? fortuna_state.pool[pl].length + event->he_size + : MAXPOOLSIZE; + + mtx_unlock(&random_reseed_mtx); +} + +/* Process a block of data suspected to be slightly stochastic */ +static void +random_fortuna_process_buffer(uint8_t *buf, u_int length) +{ + static struct harvest_event event; + u_int i, pl; + + /* We must be locked for all this as plenty of state gets messed with */ + mtx_lock(&random_reseed_mtx); + + /* F&S - P_i = P_i| + * Accumulate the data into the appropriate pools + * where each chunk will carry 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. + */ + + memset(&event, 0, sizeof(event)); + /* event.he_source = RANDOM_CACHED; */ + /* The hash_init and hash_finish are done in random_fortuna_read() below */ + for (i = 0; i < length/sizeof(uint32_t); i++) { + event.he_somecounter = get_cyclecount(); +#ifdef _KERNEL + event.he_destination = harvest_destination[RANDOM_CACHED]++; +#else + event.he_destination++; +#endif + event.he_size = sizeof(uint32_t); + *((uint32_t *)event.he_entropy) = *((uint32_t *)buf + i); +#ifdef RANDOM_DEBUG + /* XXX: FIX!! This is a dangerously tedious thing to do with mutexes held */ + { + int i; + + printf("random: %s - ", __func__); + for (i = 0; i < sizeof(event); i++) + printf("%02X", ((uint8_t *)(&event))[i]); + printf("\n"); + } +#endif + /* Do the actual entropy insertion */ + pl = event.he_destination % NPOOLS; + randomdev_hash_iterate(&fortuna_state.pool[pl].hash, &event, sizeof(event)); + /* Don't wrap the length. Doing the the hard way so as not to wrap at MAXUINT. + * XXX: FIX!!: We don't actually need lengths for anything but pool[0], + * but it's been useful debugging to see them all. + */ + fortuna_state.pool[pl].length = + (MAXPOOLSIZE - fortuna_state.pool[pl].length) > event.he_size + ? fortuna_state.pool[pl].length + event.he_size + : MAXPOOLSIZE; + } - /* Done with state-messing */ mtx_unlock(&random_reseed_mtx); } @@ -263,10 +322,10 @@ memset(hash, 0, sizeof(hash)); /* Unblock the device if it was blocked due to being unseeded */ - if (uint128_is_zero(fortuna_state.counter.whole)) + if (uint128_is_zero(fortuna_state.counter)) random_adaptor_unblock(); /* FS&K - C = C + 1 */ - uint128_increment(&fortuna_state.counter.whole); + uint128_increment(&fortuna_state.counter); } /* F&S - GenerateBlocks() */ @@ -276,13 +335,17 @@ { u_int i; +#ifdef _KERNEL + mtx_assert(&random_reseed_mtx, MA_OWNED); +#endif + for (i = 0u; i < blockcount; i++) { /* F&S - r = r|E(K,C) */ - randomdev_encrypt(&fortuna_state.key, fortuna_state.counter.byte, buf, BLOCKSIZE); + randomdev_encrypt(&fortuna_state.key, &fortuna_state.counter, buf, BLOCKSIZE); buf += BLOCKSIZE; /* F&S - C = C + 1 */ - uint128_increment(&fortuna_state.counter.whole); + uint128_increment(&fortuna_state.counter); } } @@ -296,6 +359,9 @@ /* F&S - assert(n < 2^20) */ KASSERT((bytecount <= (1 << 20)), ("invalid single read request to fortuna of %d bytes", bytecount)); +#ifdef _KERNEL + mtx_assert(&random_reseed_mtx, MA_OWNED); +#endif /* F&S - r = first-n-bytes(GenerateBlocks(ceil(n/16))) */ blockcount = bytecount / BLOCKSIZE; @@ -313,10 +379,15 @@ } /* F&S - RandomData() */ -/* Used to return processed entropy from the PRNG */ -/* The argument buf points to a whole number of blocks. */ +/* 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; @@ -329,101 +400,107 @@ /* 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 + 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) + /* F&S - Use 'getsbinuptime()' to prevent reseed-spamming. */ + && ((thistime = getsbinuptime()) - fortuna_state.lasttime > hz/10) #endif - ) { + ) { #ifdef _KERNEL - fortuna_state.lasttime = thistime; + 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)); + 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 + /* XXX: FIX!! This is a dangerously tedious thing to do with mutexes held */ + printf("random: reseedcount [%d]", fortuna_state.reseedcount); + for (i = 0; i < NPOOLS; i++) + printf(" %X", 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); } +void +random_fortuna_read(uint8_t *buf, u_int bytecount) +{ + + /* We must be locked for all this as plenty of state gets messed with */ + mtx_lock(&random_reseed_mtx); + + /* The argument buf points to a whole number of blocks. */ + random_fortuna_genrandom(buf, bytecount); + + mtx_unlock(&random_reseed_mtx); +} + +void +random_fortuna_post_read(void) +{ + + /* CWOT */ +} + /* 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; + struct randomdev_hash hash; + uint8_t junk[KEYSIZE]; uintmax_t timestamp; + randomdev_hash_init(&hash); timestamp = get_cyclecount(); - randomdev_hash_iterate(&fortuna_start_cache.hash, ×tamp, sizeof(timestamp)); - randomdev_hash_iterate(&fortuna_start_cache.hash, buf, count); + randomdev_hash_iterate(&hash, ×tamp, sizeof(timestamp)); + randomdev_hash_iterate(&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; + randomdev_hash_iterate(&hash, ×tamp, sizeof(timestamp)); + randomdev_hash_finish(&hash, junk); + memset(&hash, 0, sizeof(hash)); #ifdef RANDOM_DEBUG - printf("random: %s - ", __func__); - for (i = 0; i < KEYSIZE; i++) - printf("%02X", temp[i]); - printf("\n"); -#endif + { + int i; - 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)); + printf("random: %s - ", __func__); + for (i = 0; i < KEYSIZE; i++) + printf("%02X", junk[i]); + printf("\n"); + } +#endif - mtx_unlock(&random_reseed_mtx); + random_fortuna_process_buffer(junk, KEYSIZE); + memset(junk, 0, sizeof(junk)); } void @@ -437,7 +514,7 @@ random_fortuna_seeded(void) { - return (!uint128_is_zero(fortuna_state.counter.whole)); + return (!uint128_is_zero(fortuna_state.counter)); } #endif /* RANDOM_FORTUNA */ Index: sys/dev/random/hash.h =================================================================== --- sys/dev/random/hash.h +++ 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 @@ -47,4 +47,4 @@ 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 */ Index: sys/dev/random/hash.c =================================================================== --- sys/dev/random/hash.c +++ 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 Index: sys/dev/random/live_entropy_sources.h =================================================================== --- sys/dev/random/live_entropy_sources.h +++ sys/dev/random/live_entropy_sources.h @@ -1,6 +1,6 @@ /*- * Copyright (c) 2013 Arthur Mesh - * 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 Index: sys/dev/random/live_entropy_sources.c =================================================================== --- sys/dev/random/live_entropy_sources.c +++ sys/dev/random/live_entropy_sources.c @@ -1,6 +1,6 @@ /*- * Copyright (c) 2013 Arthur Mesh - * 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 Index: sys/dev/random/nehemiah.c =================================================================== --- sys/dev/random/nehemiah.c +++ 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 * All rights reserved. * Index: sys/dev/random/random_adaptors.h =================================================================== --- sys/dev/random/random_adaptors.h +++ sys/dev/random/random_adaptors.h @@ -1,5 +1,6 @@ /*- * Copyright (c) 2013 Arthur Mesh + * Copyright (c) 2013-2015 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,7 +34,9 @@ typedef void random_adaptor_init_func_t(void); typedef void random_adaptor_deinit_func_t(void); +typedef void random_adaptor_pre_read_func_t(void); typedef void random_adaptor_read_func_t(uint8_t *, u_int); +typedef void random_adaptor_post_read_func_t(void); 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); @@ -43,7 +46,9 @@ int ra_priority; random_adaptor_init_func_t *ra_init; random_adaptor_deinit_func_t *ra_deinit; + random_adaptor_pre_read_func_t *ra_pre_read; random_adaptor_read_func_t *ra_read; + random_adaptor_post_read_func_t *ra_post_read; random_adaptor_write_func_t *ra_write; random_adaptor_reseed_func_t *ra_reseed; random_adaptor_seeded_func_t *ra_seeded; Index: sys/dev/random/random_adaptors.c =================================================================== --- sys/dev/random/random_adaptors.c +++ sys/dev/random/random_adaptors.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2013 Mark R V Murray + * Copyright (c) 2013-2015 Mark R V Murray * Copyright (c) 2013 Arthur Mesh * Copyright (c) 2013 David E. O'Brien * All rights reserved. @@ -218,7 +218,7 @@ 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); + (random_adaptor->ra_pre_read)(); /* (Un)Blocking logic */ error = 0; @@ -235,7 +235,7 @@ __func__)); /* keep tapping away at the pre-read until we seed/unblock. */ - (random_adaptor->ra_read)(NULL, 0); + (random_adaptor->ra_pre_read)(); } mtx_lock(&random_read_rate_mtx); @@ -260,7 +260,7 @@ } /* Let the entropy source do any post-read cleanup. */ - (random_adaptor->ra_read)(NULL, 1); + (random_adaptor->ra_post_read)(); if (nbytes != uio->uio_resid && (error == ERESTART || error == EINTR) ) Index: sys/dev/random/random_harvestq.h =================================================================== --- sys/dev/random/random_harvestq.h +++ sys/dev/random/random_harvestq.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2013-2014 Mark R V Murray + * Copyright (c) 2013-2015 Mark R V Murray * Copyright (c) 2013 Arthur Mesh * All rights reserved. * @@ -45,7 +45,6 @@ }; 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 @@ -58,9 +57,6 @@ /* 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 *); Index: sys/dev/random/random_harvestq.c =================================================================== --- sys/dev/random/random_harvestq.c +++ 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. @@ -109,9 +109,6 @@ */ int harvest_pool_count; -/* <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; static void @@ -120,13 +117,11 @@ u_int maxloop, ring_out; /* - * Process until told to stop. - * * Locking is not needed as this is the only place we modify ring_out, and * we only examine ring_in without changing it. Both of these are volatile, * and this is a unique thread. */ - while (random_kthread_control >= 0) { + for (;;) { /* Deal with events, if any. Restrict the number we do in one go. */ maxloop = RANDOM_FIFO_MAX; @@ -148,32 +143,10 @@ */ 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)); + tsleep_sbt(random_kthread_proc, 0, "-", SBT_1S/10, 0, C_PREL(1)); } - - randomdev_set_wakeup_exit(&random_kthread_control); - /* 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); } /* ARGSUSED */ @@ -312,25 +285,6 @@ } -void -random_harvestq_deinit(void) -{ - -#ifdef RANDOM_DEBUG - printf("random: %s\n", __func__); -#endif - - /* - * Command the hash/reseed thread to end and wait for it to finish - */ - random_kthread_control = -1; - tsleep(&random_kthread_control, 0, "term", 0); - - mtx_destroy(&harvest_mtx); - - sysctl_ctx_free(&random_clist); -} - /* * Entropy harvesting routine. * This is supposed to be fast; do not do anything slow in here! Index: sys/dev/random/randomdev.h =================================================================== --- sys/dev/random/randomdev.h +++ 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 @@ -64,4 +64,4 @@ } #endif /* SYSCTL_DECL */ -#endif +#endif /* SYS_DEV_RANDOM_RANDOMDEV_H_INCLUDED */ Index: sys/dev/random/randomdev.c =================================================================== --- sys/dev/random/randomdev.c +++ sys/dev/random/randomdev.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000-2013 Mark R V Murray + * Copyright (c) 2000-2015 Mark R V Murray * Copyright (c) 2013 Arthur Mesh * All rights reserved. * Index: sys/dev/random/randomdev_soft.h =================================================================== --- sys/dev/random/randomdev_soft.h +++ sys/dev/random/randomdev_soft.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 @@ -36,4 +36,4 @@ void randomdev_init(void); void randomdev_deinit(void); -#endif +#endif /* SYS_DEV_RANDOM_RANDOMDEV_SOFT_H_INCLUDED */ Index: sys/dev/random/randomdev_soft.c =================================================================== --- sys/dev/random/randomdev_soft.c +++ sys/dev/random/randomdev_soft.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000-2014 Mark R V Murray + * Copyright (c) 2000-2015 Mark R V Murray * Copyright (c) 2004 Robert N. M. Watson * All rights reserved. * @@ -77,7 +77,9 @@ #define RANDOM_CSPRNG_NAME "yarrow" .ra_ident = "Yarrow", .ra_priority = 90, /* High priority, so top of the list. Fortuna may still win. */ + .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, @@ -86,7 +88,9 @@ #define RANDOM_CSPRNG_NAME "fortuna" .ra_ident = "Fortuna", .ra_priority = 100, /* High priority, so top of the list. Beat Yarrow. */ + .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, Index: sys/dev/random/uint128.h =================================================================== --- sys/dev/random/uint128.h +++ 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 @@ -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 word0; + uint64_t 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) { -#ifdef __SIZEOF_INT128__ +#ifdef USE_REAL_UINT128_T (*big_uint)++; #else - (*big_uint)[0]++; - if ((*big_uint)[0] == 0UL) - (*big_uint)[1]++; + big_uint->word0++; + if (big_uint->word0 == 0UL) + big_uint->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.word0 == 0UL && big_uint.word1 == 0UL); #endif } Index: sys/dev/random/unit_test.h =================================================================== --- sys/dev/random/unit_test.h +++ 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 @@ -32,12 +32,29 @@ void random_adaptor_unblock(void); +#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)); +} +#endif + static __inline uint64_t get_cyclecount(void) { - /* Shaddup! */ +#if defined(__amd64__) || defined(__i386__) + return (rdtsc()); +#else + /* A perfectly random number, determined by dice roll. + * See XKCD 221. + */ return (4ULL); +#endif } // #define PAGE_SIZE 4096 Index: sys/dev/random/unit_test.c =================================================================== --- sys/dev/random/unit_test.c +++ 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 @@ ../../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 @@ #include #include #include +#include #include "unit_test.h" @@ -60,8 +62,75 @@ #endif #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 == 0U) + return (0U); + + 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 @@ 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 @@ 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 @@ #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 @@ 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); Index: sys/dev/random/yarrow.h =================================================================== --- sys/dev/random/yarrow.h +++ 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 @@ -35,10 +35,12 @@ void random_yarrow_init_alg(void); void random_yarrow_deinit_alg(void); +void random_yarrow_pre_read(void); void random_yarrow_read(uint8_t *, u_int); +void random_yarrow_post_read(void); 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 */ Index: sys/dev/random/yarrow.c =================================================================== --- sys/dev/random/yarrow.c +++ 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 @@ -93,10 +93,7 @@ * Exactly one is instantiated. */ static struct yarrow_state { - union { - uint8_t byte[BLOCKSIZE]; - uint128_t whole; - } counter; /* C */ + uint128_t counter; /* C */ struct randomdev_key key; /* K */ u_int gengateinterval; /* Pg */ u_int bins; /* Pt/t */ @@ -110,11 +107,6 @@ 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; } yarrow_state; /* The random_reseed_mtx mutex protects seeding and polling/blocking. */ @@ -131,7 +123,6 @@ static u_int harvest_destination[ENTROPYSOURCE]; #endif /* _KERNEL */ -static void generator_gate(void); static void reseed(u_int); void @@ -142,9 +133,6 @@ 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); @@ -217,7 +205,7 @@ } /* Clear the counter */ - uint128_clear(&yarrow_state.counter.whole); + yarrow_state.counter = UINT128_ZERO; } void @@ -242,7 +230,7 @@ mtx_assert(&random_reseed_mtx, MA_OWNED); #endif /* Count the over-threshold sources in each pool */ - for (pl = 0; pl < 2; pl++) { + for (pl = FAST; pl <= 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) @@ -293,6 +281,10 @@ * We lock against pool state modification which can happen * during accumulation/reseeding and reading/regating */ + + /* We must be locked for all this as plenty of state gets messed with */ + mtx_lock(&random_reseed_mtx); + 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(); @@ -301,12 +293,25 @@ event.he_destination = harvest_destination[RANDOM_CACHED]++; event.he_size = sizeof(uint32_t); *((uint32_t *)event.he_entropy) = *((uint32_t *)buf + i); +#ifdef RANDOM_DEBUG + /* XXX: FIX!! This is a dangerously tedious thing to do with mutexes held */ + { + int i; + + printf("random: %s - ", __func__); + for (i = 0; i < sizeof(event); i++) + printf("%02X", ((uint8_t *)(&event))[i]); + printf("\n"); + } +#endif /* 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 */ + /* Don't do this here - do it in bulk at the end + * This 'bits' value is fake anyway. + */ yarrow_state.pool[pl].source[RANDOM_CACHED].bits += bits; #endif } @@ -314,6 +319,8 @@ yarrow_state.pool[pl].source[RANDOM_CACHED].bits += (length >> 4); random_yarrow_post_insert(); + + mtx_unlock(&random_reseed_mtx); } static void @@ -323,44 +330,40 @@ * structures static. */ static uint8_t v[TIMEBIN][KEYSIZE]; /* v[i] */ - static uint8_t hash[KEYSIZE]; /* h' */ - static uint8_t temp[KEYSIZE]; + 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")); - -#ifdef RANDOM_DEBUG -#ifdef RANDOM_DEBUG_VERBOSE - printf("random: %s %s\n", __func__, (fastslow == FAST ? "FAST" : "SLOW")); -#endif - if (!yarrow_state.seeded) { - printf("random: %s - fast - thresh %d,1 - ", __func__, yarrow_state.pool[FAST].thresh); - for (i = RANDOM_START; i < ENTROPYSOURCE; i++) - printf(" %d", yarrow_state.pool[FAST].source[i].bits); - printf("\n"); - printf("random: %s - slow - thresh %d,%d - ", __func__, yarrow_state.pool[SLOW].thresh, yarrow_state.slowoverthresh); - for (i = RANDOM_START; i < ENTROPYSOURCE; i++) - printf(" %d", yarrow_state.pool[SLOW].source[i].bits); - printf("\n"); - } -#endif #ifdef _KERNEL mtx_assert(&random_reseed_mtx, MA_OWNED); #endif +#ifdef RANDOM_DEBUG + /* XXX: FIX!! This is a dangerously tedious thing to do with mutexes held */ + printf("random: %s %s seeded = %d\n", __func__, (fastslow == FAST ? "FAST" : "SLOW"), yarrow_state.seeded); + printf("random: %s - fast - thresh %d,1 - ", __func__, yarrow_state.pool[FAST].thresh); + for (i = RANDOM_START; i < ENTROPYSOURCE; i++) + printf(" %d", yarrow_state.pool[FAST].source[i].bits); + printf("\n"); + printf("random: %s - slow - thresh %d,%d - ", __func__, yarrow_state.pool[SLOW].thresh, yarrow_state.slowoverthresh); + for (i = RANDOM_START; i < ENTROPYSOURCE; i++) + printf(" %d", yarrow_state.pool[SLOW].source[i].bits); + printf("\n"); +#endif + /* 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)); + randomdev_hash_finish(&yarrow_state.pool[SLOW].hash, &temp); + randomdev_hash_iterate(&context, &temp, sizeof(temp)); } - randomdev_hash_finish(&yarrow_state.pool[FAST].hash, temp); - randomdev_hash_iterate(&context, temp, sizeof(temp)); + randomdev_hash_finish(&yarrow_state.pool[FAST].hash, &temp); + randomdev_hash_iterate(&context, &temp, sizeof(temp)); randomdev_hash_finish(&context, v[0]); /* 2. Compute hash values for all v. _Supposed_ to be computationally @@ -389,14 +392,14 @@ 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_finish(&context, &temp); + randomdev_encrypt_init(&yarrow_state.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.counter = UINT128_ZERO; + randomdev_encrypt(&yarrow_state.key, &yarrow_state.counter, &temp, BLOCKSIZE); + yarrow_state.counter = temp; /* 5. Reset entropy estimate accumulators to zero */ @@ -407,8 +410,7 @@ /* 6. Wipe memory of intermediate values */ memset(v, 0, sizeof(v)); - memset(temp, 0, sizeof(temp)); - memset(hash, 0, sizeof(hash)); + memset(&temp, 0, sizeof(temp)); memset(&context, 0, sizeof(context)); #ifdef RANDOM_RWFILE_WRITE_IS_OK /* Not defined so writes ain't gonna happen */ @@ -428,17 +430,42 @@ } } -/* Internal function to return processed entropy from the PRNG */ +static __inline void +generator_gate(void) +{ + u_int i; + uint8_t temp[KEYSIZE]; + +#ifdef _KERNEL + mtx_assert(&random_reseed_mtx, MA_OWNED); +#endif + + uint128_increment(&yarrow_state.counter); + for (i = 0; i < KEYSIZE; i += BLOCKSIZE) + randomdev_encrypt(&yarrow_state.key, &yarrow_state.counter, temp + i, BLOCKSIZE); + + randomdev_encrypt_init(&yarrow_state.key, temp); + memset(temp, 0, KEYSIZE); +} + +/* 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. + */ +void +random_yarrow_pre_read(void) +{ +} + 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); @@ -448,69 +475,48 @@ 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; - } + uint128_increment(&yarrow_state.counter); + randomdev_encrypt(&yarrow_state.key, &yarrow_state.counter, buf, BLOCKSIZE); + buf += BLOCKSIZE; } mtx_unlock(&random_reseed_mtx); } +void +random_yarrow_post_read(void) +{ +} + /* Internal function to hand external entropy to the PRNG */ void random_yarrow_write(uint8_t *buf, u_int count) { + struct randomdev_hash hash; uintmax_t timestamp; + uint8_t junk[KEYSIZE]; - /* We must be locked for all this as plenty of state gets messed with */ - mtx_lock(&random_reseed_mtx); - + randomdev_hash_init(&hash); timestamp = get_cyclecount(); - randomdev_hash_iterate(&yarrow_state.start_cache.hash, ×tamp, sizeof(timestamp)); - randomdev_hash_iterate(&yarrow_state.start_cache.hash, buf, count); + randomdev_hash_iterate(&hash, ×tamp, sizeof(timestamp)); + randomdev_hash_iterate(&hash, buf, count); timestamp = get_cyclecount(); - randomdev_hash_iterate(&yarrow_state.start_cache.hash, ×tamp, sizeof(timestamp)); - randomdev_hash_finish(&yarrow_state.start_cache.hash, yarrow_state.start_cache.junk); - randomdev_hash_init(&yarrow_state.start_cache.hash); + randomdev_hash_iterate(&hash, ×tamp, sizeof(timestamp)); + randomdev_hash_finish(&hash, junk); -#ifdef RANDOM_DEBUG_VERBOSE +#ifdef RANDOM_DEBUG { int i; printf("random: %s - ", __func__); for (i = 0; i < KEYSIZE; i++) - printf("%02X", yarrow_state.start_cache.junk[i]); + printf("%02X", 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); -} - -static void -generator_gate(void) -{ - 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); + random_yarrow_process_buffer(junk, KEYSIZE); + memset(junk, 0, KEYSIZE); } void