Index: sys/dev/random/fortuna.c =================================================================== --- sys/dev/random/fortuna.c +++ sys/dev/random/fortuna.c @@ -71,6 +71,7 @@ #include #include +#include #include #include #endif /* _KERNEL */ @@ -125,26 +126,26 @@ static void random_fortuna_pre_read(void); static void random_fortuna_read(uint8_t *, u_int); -static void random_fortuna_post_read(void); static void random_fortuna_write(uint8_t *, u_int); static void random_fortuna_reseed(void); static int random_fortuna_seeded(void); static void random_fortuna_process_event(struct harvest_event *); +static void random_fortuna_init_alg(void *); +static void random_fortuna_deinit_alg(void *); -#ifdef _KERNEL /* Interface to Adaptors system */ struct random_algorithm random_alg_context = { .ra_ident = "Fortuna", + .ra_init_alg = random_fortuna_init_alg, + .ra_deinit_alg = random_fortuna_deinit_alg, .ra_pre_read = random_fortuna_pre_read, .ra_read = random_fortuna_read, - .ra_post_read = random_fortuna_post_read, .ra_write = random_fortuna_write, .ra_reseed = random_fortuna_reseed, .ra_seeded = random_fortuna_seeded, .ra_event_processor = random_fortuna_process_event, .ra_poolcount = RANDOM_FORTUNA_NPOOLS, }; -#endif /* ARGSUSED */ static void @@ -251,29 +252,6 @@ } /*- - * Process a block of data suspected to be slightly stochastic. - * Do this by breaking it up and inserting the pieces as if - * they were separate events. - */ -static void -random_fortuna_process_buffer(uint32_t *buf, u_int wordcount) -{ - static struct harvest_event event; - static u_int destination = 0; - int i; - - for (i = 0; i < wordcount; i += sizeof(event.he_entropy)/sizeof(event.he_entropy[0])) { - event.he_somecounter = (uint32_t)get_cyclecount(); - event.he_size = sizeof(event.he_entropy); - event.he_bits = event.he_size/8; - event.he_source = RANDOM_CACHED; - event.he_destination = destination++; /* Harmless cheating */ - memcpy(event.he_entropy, buf + i, sizeof(event.he_entropy)); - random_fortuna_process_event(&event); - } -} - -/*- * FS&K - Reseed() * This introduces new key material into the output generator. * Additionaly it increments the output generator's counter @@ -358,13 +336,10 @@ } /*- - * FS&K - RandomData() - * Used to return processed entropy from the PRNG. - * There is a pre_read and a post_read required to be present - * (but they can be null functions) in order to allow specific - * actions at the begin or the end of a read. Fortuna does its - * reseeding in the _pre_read() part, and _post_read() is not - * used. + * FS&K - RandomData() (Part 1) + * Used to return processed entropy from the PRNG. There is a pre_read + * required to be present (but it can be a stub) in order to allow + * specific actions at the begin of the read. */ void random_fortuna_pre_read(void) @@ -435,8 +410,10 @@ } /*- - * Main read from Fortuna. - * The supplied buf MUST be a multiple (>=0) of RANDOM_BLOCKSIZE in size. + * FS&K - RandomData() (Part 2) + * Main read from Fortuna, continued. May be called multiple times after + * the random_fortuna_pre_read() above. + * The supplied buf MUST be a multiple of RANDOM_BLOCKSIZE in size. * Lots of code presumes this for efficiency, both here and in other * routines. You are NOT allowed to break this! */ @@ -444,24 +421,22 @@ random_fortuna_read(uint8_t *buf, u_int bytecount) { + KASSERT(buf != 0, ("random_fortuna_read(): bytecount must be > 0")); + KASSERT((buf % RANDOM_BLOCKSIZE) == 0, ("random_fortuna_read(): bytecount must be a multiple of" #RANDOM_BLOCKSIZE)); RANDOM_RESEED_LOCK(); random_fortuna_genrandom(buf, bytecount); RANDOM_RESEED_UNLOCK(); } -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) { + static u_int destination = 0; + struct harvest_event event; struct randomdev_hash hash; uint32_t entropy_data[RANDOM_KEYSIZE_WORDS], timestamp; + int i; /* Extra timing here is helpful to scrape scheduler timing entropy */ randomdev_hash_init(&hash); @@ -472,15 +447,21 @@ randomdev_hash_iterate(&hash, ×tamp, sizeof(timestamp)); randomdev_hash_finish(&hash, entropy_data); explicit_bzero(&hash, sizeof(hash)); - random_fortuna_process_buffer(entropy_data, sizeof(entropy_data)/sizeof(entropy_data[0])); + for (i = 0; i < RANDOM_KEYSIZE_WORDS; i += sizeof(event.he_entropy)/sizeof(event.he_entropy[0])) { + event.he_somecounter = (uint32_t)get_cyclecount(); + event.he_size = sizeof(event.he_entropy); + event.he_bits = event.he_size/8; + event.he_source = RANDOM_CACHED; + event.he_destination = destination++; /* Harmless cheating */ + memcpy(event.he_entropy, entropy_data + i, sizeof(event.he_entropy)); + random_fortuna_process_event(&event); + } explicit_bzero(entropy_data, sizeof(entropy_data)); } void random_fortuna_reseed(void) { - - /* CWOT */ } int Index: sys/dev/random/hash.h =================================================================== --- sys/dev/random/hash.h +++ sys/dev/random/hash.h @@ -29,18 +29,21 @@ #ifndef SYS_DEV_RANDOM_HASH_H_INCLUDED #define SYS_DEV_RANDOM_HASH_H_INCLUDED +/* Keys are formed from cipher blocks */ #define RANDOM_KEYSIZE 32 /* (in bytes) == 256 bits */ #define RANDOM_KEYSIZE_WORDS (RANDOM_KEYSIZE/sizeof(uint32_t)) #define RANDOM_BLOCKSIZE 16 /* (in bytes) == 128 bits */ #define RANDOM_BLOCKSIZE_WORDS (RANDOM_BLOCKSIZE/sizeof(uint32_t)) #define RANDOM_KEYS_PER_BLOCK (RANDOM_KEYSIZE/RANDOM_BLOCKSIZE) + +/* The size of the zero block portion used to form H_d(m) */ #define RANDOM_ZERO_BLOCKSIZE 64 /* (in bytes) == 512 zero bits */ -struct randomdev_hash { /* Big! Make static! */ +struct randomdev_hash { SHA256_CTX sha; }; -struct randomdev_key { /* Big! Make static! */ +struct randomdev_key { keyInstance key; /* Key schedule */ cipherInstance cipher; /* Rijndael internal */ }; Index: sys/dev/random/random_harvestq.c =================================================================== --- sys/dev/random/random_harvestq.c +++ sys/dev/random/random_harvestq.c @@ -74,8 +74,8 @@ * this make is a bit easier to lock and protect. */ static struct harvest_context { - /* The harvest mutex protects the consistency of the entropy Fifos and - * empty fifo and other associated structures. + /* The harvest mutex protects all of harvest_context and + * the related data. */ struct mtx hc_mtx; /* Round-robin destination cache. */ @@ -95,6 +95,9 @@ * If (ring.in + 1) == ring.out (mod RANDOM_RING_MAX), * the buffer is full. * + * NOTE: ring.in points to the last added element, + * and ring.out points to the last consumed element. + * * The ring.in variable needs locking as there are multiple * sources to the ring. Only the sources may change ring.in, * but the consumer may examine it. @@ -110,7 +113,7 @@ } hc_entropy_ring; struct fast_entropy_accumulator { volatile u_int pos; - uint32_t buf[8]; + uint32_t buf[RANDOM_RING_MAX]; } hc_entropy_fast_accumulator; } harvest_context; @@ -150,7 +153,7 @@ break; } random_sources_feed(); - /* XXX: FIX!! This This seems a little slow; 8 items every 0.1s from UMA? */ + /* XXX: FIX!! Increase the high-performance data rate? Need some measurements first. */ for (i = 0; i < RANDOM_ACCUM_MAX; i++) { if (harvest_context.hc_entropy_fast_accumulator.buf[i]) { random_harvest_direct(harvest_context.hc_entropy_fast_accumulator.buf + i, sizeof(harvest_context.hc_entropy_fast_accumulator.buf[0]), 4, RANDOM_FAST); @@ -285,6 +288,8 @@ if (keyfile != NULL) { data = preload_fetch_addr(keyfile); size = preload_fetch_size(keyfile); + /* Trim the size. If the admin has a file with a funny size, we lose some. Tough. */ + size -= (size % sizeof(event.he_entropy)); if (data != NULL && size != 0) { for (i = 0; i < size; i += sizeof(event.he_entropy)) { count = sizeof(event.he_entropy); @@ -334,7 +339,7 @@ * read which can be quite expensive. */ void -random_harvest_queue(const void *entropy, u_int count, u_int bits, enum random_entropy_source origin) +random_harvest_queue(const void *entropy, u_int size, u_int bits, enum random_entropy_source origin) { struct harvest_event *event; u_int ring_in; @@ -351,14 +356,14 @@ event->he_source = origin; event->he_destination = harvest_context.hc_destination[origin]++; event->he_bits = bits; - if (count <= sizeof(event->he_entropy)) { - event->he_size = count; - memcpy(event->he_entropy, entropy, count); + if (size <= sizeof(event->he_entropy)) { + event->he_size = size; + memcpy(event->he_entropy, entropy, size); } else { /* Big event, so squash it */ event->he_size = sizeof(event->he_entropy[0]); - event->he_entropy[0] = jenkins_hash(entropy, count, (uint32_t)(uintptr_t)event); + event->he_entropy[0] = jenkins_hash(entropy, size, (uint32_t)(uintptr_t)event); } harvest_context.hc_entropy_ring.in = ring_in; } @@ -372,7 +377,7 @@ * This is the right place for high-rate harvested data. */ void -random_harvest_fast(const void *entropy, u_int count, u_int bits, enum random_entropy_source origin) +random_harvest_fast(const void *entropy, u_int size, u_int bits, enum random_entropy_source origin) { u_int pos; @@ -381,7 +386,7 @@ if (!(harvest_context.hc_source_mask & (1 << origin))) return; pos = harvest_context.hc_entropy_fast_accumulator.pos; - harvest_context.hc_entropy_fast_accumulator.buf[pos] ^= jenkins_hash(entropy, count, (uint32_t)get_cyclecount()); + harvest_context.hc_entropy_fast_accumulator.buf[pos] ^= jenkins_hash(entropy, size, (uint32_t)get_cyclecount()); harvest_context.hc_entropy_fast_accumulator.pos = (pos + 1)%RANDOM_ACCUM_MAX; } @@ -392,20 +397,20 @@ * (e.g.) booting when initial entropy is being gathered. */ void -random_harvest_direct(const void *entropy, u_int count, u_int bits, enum random_entropy_source origin) +random_harvest_direct(const void *entropy, u_int size, u_int bits, enum random_entropy_source origin) { struct harvest_event event; KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, ("%s: origin %d invalid\n", __func__, origin)); if (!(harvest_context.hc_source_mask & (1 << origin))) return; - count = MIN(count, sizeof(event.he_entropy)); + size = MIN(size, sizeof(event.he_entropy)); event.he_somecounter = (uint32_t)get_cyclecount(); - event.he_size = count; + event.he_size = size; event.he_bits = bits; event.he_source = origin; event.he_destination = harvest_context.hc_destination[origin]++; - memcpy(event.he_entropy, entropy, count); + memcpy(event.he_entropy, entropy, size); random_harvestq_fast_process_event(&event); explicit_bzero(&event, sizeof(event)); } Index: sys/dev/random/randomdev.h =================================================================== --- sys/dev/random/randomdev.h +++ sys/dev/random/randomdev.h @@ -29,6 +29,8 @@ #ifndef SYS_DEV_RANDOM_RANDOMDEV_H_INCLUDED #define SYS_DEV_RANDOM_RANDOMDEV_H_INCLUDED +#ifdef _KERNEL + /* This header contains only those definitions that are global * and non algorithm-specific for the entropy processor */ @@ -55,11 +57,12 @@ #define RANDOM_ALG_READ_RATE_MINIMUM 32 +#endif /* _KERNEL */ + struct harvest_event; typedef void random_alg_pre_read_t(void); typedef void random_alg_read_t(uint8_t *, u_int); -typedef void random_alg_post_read_t(void); typedef void random_alg_write_t(uint8_t *, u_int); typedef int random_alg_seeded_t(void); typedef void random_alg_reseed_t(void); @@ -74,9 +77,10 @@ struct random_algorithm { const char *ra_ident; u_int ra_poolcount; + void (*ra_init_alg)(void *); + void (*ra_deinit_alg)(void *); random_alg_pre_read_t *ra_pre_read; random_alg_read_t *ra_read; - random_alg_post_read_t *ra_post_read; random_alg_write_t *ra_write; random_alg_reseed_t *ra_reseed; random_alg_seeded_t *ra_seeded; @@ -85,6 +89,8 @@ extern struct random_algorithm random_alg_context; +#ifdef _KERNEL + /* * Random Source is a source of entropy that can provide * specified or approximate amount of entropy immediately @@ -108,6 +114,8 @@ void random_sources_feed(void); +#endif /* _KERNEL */ + void randomdev_unblock(void); #endif /* SYS_DEV_RANDOM_RANDOMDEV_H_INCLUDED */ Index: sys/dev/random/randomdev.c =================================================================== --- sys/dev/random/randomdev.c +++ sys/dev/random/randomdev.c @@ -111,7 +111,6 @@ .ra_seeded = (random_alg_seeded_t *)dummy_random_zero, .ra_pre_read = dummy_random, .ra_read = (random_alg_read_t *)dummy_random_zero, - .ra_post_read = dummy_random, .ra_write = (random_alg_write_t *)dummy_random_zero, .ra_event_processor = NULL, .ra_poolcount = 0, @@ -142,15 +141,15 @@ random_alg_context.ra_pre_read(); /* (Un)Blocking logic */ error = 0; - while (!random_alg_context.ra_seeded() && error == 0) { + while (!random_alg_context.ra_seeded()) { if (flags & O_NONBLOCK) { error = EWOULDBLOCK; break; } - tsleep(&random_alg_context, 0, "randrd", hz/10); + tsleep(&random_alg_context, 0, "randseed", hz/10); /* keep tapping away at the pre-read until we seed/unblock. */ random_alg_context.ra_pre_read(); - printf("random: %s unblock (error = %d)\n", __func__, error); + printf("random: %s unblock wait\n", __func__); } if (error == 0) { #if !defined(RANDOM_DUMMY) @@ -163,7 +162,6 @@ random_alg_context.ra_read(random_buf, c); error = uiomove(random_buf, c, uio); } - random_alg_context.ra_post_read(); if (nbytes != uio->uio_resid && (error == ERESTART || error == EINTR) ) /* Return partial read, not error. */ error = 0; @@ -204,7 +202,6 @@ memcpy(random_buf, local_buf, len); } else len = 0; - random_alg_context.ra_post_read(); return (len); } Index: sys/dev/random/unit_test.h =================================================================== --- sys/dev/random/unit_test.h +++ sys/dev/random/unit_test.h @@ -34,7 +34,9 @@ #error "Random unit tests cannot be compiled into the kernel." #endif -void random_adaptor_unblock(void); +#include +#include +#include #if defined(clang) && __has_builtin(__builtin_readcyclecounter) #define rdtsc __builtin_readcyclecounter Index: sys/dev/random/unit_test.c =================================================================== --- sys/dev/random/unit_test.c +++ sys/dev/random/unit_test.c @@ -52,15 +52,9 @@ #include #include +#include "randomdev.h" #include "unit_test.h" -#ifdef RANDOM_YARROW -#include "dev/random/yarrow.h" -#endif -#ifdef RANDOM_FORTUNA -#include "dev/random/fortuna.h" -#endif - #define NUM_THREADS 3 #define DEBUG @@ -133,7 +127,7 @@ } void -random_adaptor_unblock(void) +randomdev_unblock(void) { #if 0 @@ -166,12 +160,7 @@ e.he_destination = i; e.he_source = (i + 3)%7; e.he_next = NULL; -#ifdef RANDOM_YARROW - random_yarrow_process_event(&e); -#endif -#ifdef RANDOM_FORTUNA - random_fortuna_process_event(&e); -#endif + random_alg_context.ra_event_processor(&e); usleep(r); } @@ -198,12 +187,7 @@ printf("Thread write 1 - %d\n", i); if (buf != NULL) { printf("Thread 1 writing.\n"); -#ifdef RANDOM_YARROW - random_yarrow_write(buf, i); -#endif -#ifdef RANDOM_FORTUNA - random_fortuna_write(buf, i); -#endif + random_alg_context.ra_write(buf, i); free(buf); } usleep(1000000); @@ -229,21 +213,9 @@ tid = (size_t)threadid; printf("Thread #%zd starts\n", tid); -#ifdef RANDOM_YARROW - while (!random_yarrow_seeded()) -#endif -#ifdef RANDOM_FORTUNA - while (!random_fortuna_seeded()) -#endif + while (!random_alg_context.ra_seeded()) { -#ifdef RANDOM_YARROW - random_yarrow_pre_read(); - random_yarrow_post_read(); -#endif -#ifdef RANDOM_FORTUNA - random_fortuna_pre_read(); - random_fortuna_post_read(); -#endif + random_alg_context.ra_pre_read(); usleep(100); } @@ -253,16 +225,8 @@ if (i % 1000 == 0) printf("Thread read %zd - %d\n", tid, i); if (buf != NULL && zbuf != NULL) { -#ifdef RANDOM_YARROW - random_yarrow_pre_read(); - random_yarrow_read(buf, i); - random_yarrow_post_read(); -#endif -#ifdef RANDOM_FORTUNA - random_fortuna_pre_read(); - random_fortuna_read(buf, i); - random_fortuna_post_read(); -#endif + random_alg_context.ra_pre_read(); + random_alg_context.ra_read(buf, i); zsize = block_deflate(buf, zbuf, i); if (zsize < i) printf("ERROR!! Compressible RNG output!\n"); @@ -300,12 +264,7 @@ int rc; long t; -#ifdef RANDOM_YARROW - random_yarrow_init_alg(); -#endif -#ifdef RANDOM_FORTUNA - random_fortuna_init_alg(); -#endif + random_alg_context.ra_init_alg(NULL); for (t = 0; t < NUM_THREADS; t++) { printf("In main: creating thread %ld\n", t); @@ -324,12 +283,7 @@ thrd_join(threads[1], &rc); thrd_join(threads[0], &rc); -#ifdef RANDOM_YARROW - random_yarrow_deinit_alg(); -#endif -#ifdef RANDOM_FORTUNA - random_fortuna_deinit_alg(); -#endif + random_alg_context.ra_deinit_alg(NULL); /* Last thing that main() should do */ thrd_exit(0); Index: sys/dev/random/yarrow.c =================================================================== --- sys/dev/random/yarrow.c +++ sys/dev/random/yarrow.c @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -63,6 +64,7 @@ #include #include +#include #include #include #endif /* _KERNEL */ @@ -109,27 +111,27 @@ static void random_yarrow_pre_read(void); static void random_yarrow_read(uint8_t *, u_int); -static void random_yarrow_post_read(void); static void random_yarrow_write(uint8_t *, u_int); static void random_yarrow_reseed(void); static int random_yarrow_seeded(void); static void random_yarrow_reseed_internal(u_int); static void random_yarrow_process_event(struct harvest_event *); +static void random_yarrow_init_alg(void *); +static void random_yarrow_deinit_alg(void *); -#ifdef _KERNEL /* Interface to Adaptors system */ struct random_algorithm random_alg_context = { .ra_ident = "Yarrow", + .ra_init_alg = random_yarrow_init_alg, + .ra_deinit_alg = random_yarrow_deinit_alg, .ra_pre_read = random_yarrow_pre_read, .ra_read = random_yarrow_read, - .ra_post_read = random_yarrow_post_read, .ra_write = random_yarrow_write, .ra_reseed = random_yarrow_reseed, .ra_seeded = random_yarrow_seeded, .ra_event_processor = random_yarrow_process_event, .ra_poolcount = RANDOM_YARROW_NPOOLS, }; -#endif /* ARGSUSED */ static void @@ -384,12 +386,11 @@ } /*- - * Used to return processed entropy from the PRNG. - * There is a pre_read and a post_read required to be present - * (but they can be null functions) in order to allow specific - * actions at the begin or the end of a read. Yarrow does its - * reseeding in its own thread. The _pre_read() and _post_read() - * are not used here, and must be kept for completeness. + * Used to return processed entropy from the PRNG. There is a pre_read + * required to be present (but it can be a stub) in order to allow + * specific actions at the begin of the read. + * Yarrow does its reseeding in its own thread; _pre_read() is not used + * by Yarrow but must be kept for completeness. */ void random_yarrow_pre_read(void) @@ -421,13 +422,6 @@ RANDOM_RESEED_UNLOCK(); } -void -random_yarrow_post_read(void) -{ - - /* CWOT */ -} - /* Internal function to hand external entropy to the PRNG. */ void random_yarrow_write(uint8_t *buf, u_int count)