From owner-svn-src-projects@FreeBSD.ORG Mon Nov 25 21:30:47 2013 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 62B8DBE1; Mon, 25 Nov 2013 21:30:47 +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)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 50B082B0C; Mon, 25 Nov 2013 21:30:47 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id rAPLUlVm045469; Mon, 25 Nov 2013 21:30:47 GMT (envelope-from markm@svn.freebsd.org) Received: (from markm@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id rAPLUjdE045460; Mon, 25 Nov 2013 21:30:45 GMT (envelope-from markm@svn.freebsd.org) Message-Id: <201311252130.rAPLUjdE045460@svn.freebsd.org> From: Mark Murray Date: Mon, 25 Nov 2013 21:30:45 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r258598 - in projects/random_number_generator: share/examples/kld/random_adaptor sys/dev/random sys/kern sys/sys X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 25 Nov 2013 21:30:47 -0000 Author: markm Date: Mon Nov 25 21:30:45 2013 New Revision: 258598 URL: http://svnweb.freebsd.org/changeset/base/258598 Log: Snapshot. * More fixing of locking. * Re-add write mode; this is nowhwere near finished, but has the beginnings of functionality. It needs to have a low impact if an "overwhelm" attack is mounted. * Add unit test (again not finished by any means - in fact its disgusting). * More tweeking, simplifying and reviewing. * And with little fanfare, the first public exposure of my new Fortuna code! Don't try to run the above; its not ready for primetime yet. M Added: projects/random_number_generator/sys/dev/random/build.sh (contents, props changed) projects/random_number_generator/sys/dev/random/fortuna.c (contents, props changed) projects/random_number_generator/sys/dev/random/fortuna.h (contents, props changed) projects/random_number_generator/sys/dev/random/unit_test.c (contents, props changed) projects/random_number_generator/sys/dev/random/unit_test.h (contents, props changed) Modified: projects/random_number_generator/share/examples/kld/random_adaptor/random_adaptor_example.c projects/random_number_generator/sys/dev/random/hash.c projects/random_number_generator/sys/dev/random/random_adaptors.c projects/random_number_generator/sys/dev/random/random_adaptors.h projects/random_number_generator/sys/dev/random/random_harvestq.c projects/random_number_generator/sys/dev/random/randomdev.c projects/random_number_generator/sys/dev/random/yarrow.c projects/random_number_generator/sys/dev/random/yarrow.h projects/random_number_generator/sys/kern/subr_bus.c projects/random_number_generator/sys/sys/random.h Modified: projects/random_number_generator/share/examples/kld/random_adaptor/random_adaptor_example.c ============================================================================== --- projects/random_number_generator/share/examples/kld/random_adaptor/random_adaptor_example.c Mon Nov 25 21:17:14 2013 (r258597) +++ projects/random_number_generator/share/examples/kld/random_adaptor/random_adaptor_example.c Mon Nov 25 21:30:45 2013 (r258598) @@ -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); Added: projects/random_number_generator/sys/dev/random/build.sh ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/random_number_generator/sys/dev/random/build.sh Mon Nov 25 21:30:45 2013 (r258598) @@ -0,0 +1,2 @@ +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 -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 -o funit_test Added: projects/random_number_generator/sys/dev/random/fortuna.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/random_number_generator/sys/dev/random/fortuna.c Mon Nov 25 21:30:45 2013 (r258598) @@ -0,0 +1,433 @@ +/*- + * Copyright (c) 2013 Mark R V Murray + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +__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 +#endif /* _KERNEL */ + +#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 */ + + /* The reseed thread mutex */ + mtx_t *reseed_mtx; + +#ifdef _KERNEL + /* For use when 'pacing' the reseeds */ + sbintime_t lasttime; +#endif +} fortuna_state; + +static struct fortuna_start_cache { + uint8_t junk[PAGE_SIZE]; + size_t length; + struct randomdev_hash hash; +} fortuna_start_cache; + +#ifdef _KERNEL +RANDOM_CHECK_UINT(minpoolsize, MINPOOLSIZE, MAXPOOLSIZE); +#endif + +void +random_fortuna_init_alg(struct sysctl_ctx_list *clist, mtx_t *lock) +{ + int i; +#ifdef _KERNEL + struct sysctl_oid *random_fortuna_o; +#endif + +#ifdef RANDOM_DEBUG + printf("random: %s\n", __func__); +#endif + + memset((void *)(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 */ + fortuna_state.reseed_mtx = lock; + +#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(clist, + SYSCTL_STATIC_CHILDREN(_kern_random), + OID_AUTO, "fortuna", CTLFLAG_RW, 0, + "Fortuna Parameters"); + + SYSCTL_ADD_PROC(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 */ + fortuna_state.counter.whole = 0ULL; + + /* F&S - K = 0 */ + memset((void *)(&fortuna_state.key), 0, sizeof(struct randomdev_key)); +} + +void +random_fortuna_deinit_alg(void) +{ + +#ifdef RANDOM_DEBUG + printf("random: %s\n", __func__); +#endif + memset((void *)(&fortuna_state), 0, sizeof(struct 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(fortuna_state.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(fortuna_state.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 RANDOM_DEBUG + printf("random: %s %d %u\n", __func__, (fortuna_state.counter.whole != 0ULL), length); +#endif +#ifdef _KERNEL + mtx_assert(fortuna_state.reseed_mtx, MA_OWNED); +#endif + + /* F&S - temp = H(K|s) */ + randomdev_hash_init(&context); + randomdev_hash_iterate(&context, &fortuna_state.key, sizeof(struct randomdev_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((void *)temp, 0, sizeof(temp)); + memset((void *)hash, 0, sizeof(hash)); + + /* Unblock the device if it was blocked due to being unseeded */ + if (fortuna_state.counter.whole == 0ULL) + random_adaptor_unblock(); + + /* F&S - C = C + 1 */ + 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 */ + 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((void *)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(fortuna_state.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 */ +#ifdef RANDOM_DEBUG + printf("random: active reseed: reseedcount [%d] [", fortuna_state.reseedcount); +#endif + for (i = 0; i < NPOOLS; i++) { + /* F&S - if Divides(ReseedCnt, 2^i) ... */ + if ((fortuna_state.reseedcount % (1 << i)) == 0U) { +#ifdef RANDOM_DEBUG + printf(" %d", i); +#endif + 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(" ]\n"); + printf("random: active reseed: "); + for (i = 0; i < NPOOLS; i++) + printf(" %d", fortuna_state.pool[i].length); + printf("\n"); +#endif + /* F&S */ + reseed(s, seedlength); + + /* Clean up */ + memset((void *)s, 0, seedlength); + seedlength = 0U; + memset((void *)temp, 0, sizeof(temp)); + memset((void *)&context, 0, sizeof(context)); + } + } + } + /* if buf != NULL do a regular read. */ + else + random_fortuna_genrandom(buf, bytecount); + + mtx_unlock(fortuna_state.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; + + /* We must be locked for all this as plenty of state gets messed with */ + mtx_lock(fortuna_state.reseed_mtx); + + 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((void *)(temp), 0, KEYSIZE); + randomdev_hash_init(&fortuna_start_cache.hash); + + reseed(fortuna_start_cache.junk, MIN(PAGE_SIZE, fortuna_start_cache.length)); + memset((void *)(fortuna_start_cache.junk), 0, sizeof(fortuna_start_cache.junk)); + + mtx_unlock(fortuna_state.reseed_mtx); +} + +void +random_fortuna_reseed(void) +{ + + /* CWOT */ +} + +int +random_fortuna_seeded(void) +{ + + return (fortuna_state.counter.whole != 0ULL); +} Added: projects/random_number_generator/sys/dev/random/fortuna.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/random_number_generator/sys/dev/random/fortuna.h Mon Nov 25 21:30:45 2013 (r258598) @@ -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(struct sysctl_ctx_list *, mtx_t *); +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: projects/random_number_generator/sys/dev/random/hash.c ============================================================================== --- projects/random_number_generator/sys/dev/random/hash.c Mon Nov 25 21:17:14 2013 (r258597) +++ projects/random_number_generator/sys/dev/random/hash.c Mon Nov 25 21:30:45 2013 (r258598) @@ -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); } @@ -77,5 +95,6 @@ randomdev_encrypt_init(struct randomdev_ void 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: projects/random_number_generator/sys/dev/random/random_adaptors.c ============================================================================== --- projects/random_number_generator/sys/dev/random/random_adaptors.c Mon Nov 25 21:17:14 2013 (r258597) +++ projects/random_number_generator/sys/dev/random/random_adaptors.c Mon Nov 25 21:30:45 2013 (r258598) @@ -1,7 +1,7 @@ /*- + * Copyright (c) 2013 Mark R V Murray * Copyright (c) 2013 Arthur Mesh * Copyright (c) 2013 David E. O'Brien - * Copyright (c) 2013 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -62,15 +62,16 @@ static struct adaptors_head random_adapt static struct random_adaptor *random_adaptor = NULL; /* Currently active adaptor */ /* End of data items requiring random_adaptors_lock protection */ -/* The random_rate_mtx mutex protects the consistency of the read-rate logic. */ -struct mtx random_rate_mtx; -int random_adaptor_read_rate_cache; -/* End of data items requiring random_rate_mtx mutex protection */ +/* The random_readrate_mtx mutex protects the read-rate estimator. + */ +static struct mtx random_read_rate_mtx; +static int random_adaptor_read_rate_cache; +/* End of data items requiring random_readrate_mtx mutex protection */ /* The random_reseed_mtx mutex protects seeding and polling/blocking. * This is passed into the software entropy hasher/processor. */ -struct mtx random_reseed_mtx; +static struct mtx random_reseed_mtx; /* End of data items requiring random_reseed_mtx mutex protection */ static struct selinfo rsel; @@ -191,123 +192,71 @@ random_adaptor_deregister(const char *na free(rra, M_ENTROPY); } -/* - * Per-instance structure. - * - * List of locks - * XXX: FIX!! - */ -struct random_adaptor_softc { - int oink; - int tweet; -}; - -static void -random_adaptor_dtor(void *data) -{ - struct random_adaptor_softc *ras = data; - - free(ras, M_ENTROPY); -} - /* ARGSUSED */ int -random_adaptor_open(struct cdev *dev __unused, int flags, int mode __unused, struct thread *td __unused) +random_adaptor_read(struct cdev *dev __unused, struct uio *uio, int flags) { - struct random_adaptor_softc *ras; + void *random_buf; + int c, error; + ssize_t nbytes; KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__)); - ras = malloc(sizeof(struct random_adaptor_softc), M_ENTROPY, M_WAITOK|M_ZERO); - /* XXX: FIX!! Set up softc here */ - - devfs_set_cdevpriv(ras, random_adaptor_dtor); + sx_slock(&random_adaptors_lock); - /* Give the source a chance to do some pre-read/write startup */ - if (flags & FREAD) { - sx_slock(&random_adaptors_lock); - (random_adaptor->ra_read)(NULL, 0); - sx_sunlock(&random_adaptors_lock); - } else if (flags & FWRITE) { - sx_slock(&random_adaptors_lock); - (random_adaptor->ra_write)(NULL, 0); - sx_sunlock(&random_adaptors_lock); - } + mtx_lock(&random_reseed_mtx); - return (0); -} + /* Let the entropy source do any pre-read setup. */ + (random_adaptor->ra_read)(NULL, 0); -/* ARGSUSED */ -int -random_adaptor_close(struct cdev *dev __unused, int flags, int fmt __unused, struct thread *td __unused) -{ + /* (Un)Blocking logic */ + error = 0; + while (!random_adaptor->ra_seeded()) { + if (flags & O_NONBLOCK) { + error = EWOULDBLOCK; + break; + } - KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__)); + /* Sleep instead of going into a spin-frenzy */ + msleep(&random_adaptor, &random_reseed_mtx, PUSER | PCATCH, "block", hz/10); - /* Give the source a chance to do some post-read/write shutdown */ - if (flags & FREAD) { - sx_slock(&random_adaptors_lock); - (random_adaptor->ra_read)(NULL, 1); - sx_sunlock(&random_adaptors_lock); - } else if (flags & FWRITE) { - sx_slock(&random_adaptors_lock); - (random_adaptor->ra_write)(NULL, 1); - sx_sunlock(&random_adaptors_lock); + /* keep tapping away at the pre-read until we seed/unblock. */ + (random_adaptor->ra_read)(NULL, 0); } - return (0); -} - -/* ARGSUSED */ -int -random_adaptor_read(struct cdev *dev __unused, struct uio *uio, int flags __unused) -{ - void *random_buf; - int c, error; - u_int npages; - struct random_adaptor_softc *ras; + mtx_unlock(&random_reseed_mtx); - KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__)); + mtx_lock(&random_read_rate_mtx); - error = devfs_get_cdevpriv((void **)&ras); - if (error == 0) { + /* The read-rate stuff is a rough indication of the instantaneous read rate, + * used to increase the use of 'live' entropy sources when lots of reads are done. + */ + nbytes = (uio->uio_resid + 32 - 1)/32; /* Round up to units of 32 */ + random_adaptor_read_rate_cache += nbytes*32; + random_adaptor_read_rate_cache = MIN(random_adaptor_read_rate_cache, 32); - sx_slock(&random_adaptors_lock); + mtx_unlock(&random_read_rate_mtx); - /* Blocking logic */ - mtx_lock(&random_reseed_mtx); - while (!random_adaptor->ra_seeded() && !error) { - if (flags & O_NONBLOCK) - error = EWOULDBLOCK; - else - error = msleep(&random_adaptor, &random_reseed_mtx, PUSER | PCATCH, "block", 0); - } - mtx_unlock(&random_reseed_mtx); + if (!error) { /* The actual read */ - if (!error) { - /* The read-rate stuff is a *VERY* crude indication of the instantaneous read rate, - * designed to increase the use of 'live' entropy sources when lots of reads are done. - */ - mtx_lock(&random_rate_mtx); - npages = (uio->uio_resid + PAGE_SIZE - 1)/PAGE_SIZE; - random_adaptor_read_rate_cache += npages; - random_adaptor_read_rate_cache = MIN(random_adaptor_read_rate_cache, 32); - mtx_unlock(&random_rate_mtx); - - random_buf = (void *)malloc(npages*PAGE_SIZE, M_ENTROPY, M_WAITOK); - while (uio->uio_resid > 0 && !error) { - c = MIN(uio->uio_resid, npages*PAGE_SIZE); - (random_adaptor->ra_read)(random_buf, c); - error = uiomove(random_buf, c, uio); - } - free(random_buf, M_ENTROPY); + + random_buf = (void *)malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK); + + while (uio->uio_resid && !error) { + c = MIN(uio->uio_resid, PAGE_SIZE); + (random_adaptor->ra_read)(random_buf, c); + error = uiomove(random_buf, c, uio); } - sx_sunlock(&random_adaptors_lock); + /* Let the entropy source do any post-read cleanup. */ + (random_adaptor->ra_read)(NULL, 1); + free(random_buf, M_ENTROPY); } + sx_sunlock(&random_adaptors_lock); + return (error); } @@ -318,9 +267,12 @@ random_adaptor_read_rate(void) KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__)); - mtx_lock(&random_rate_mtx); + mtx_lock(&random_read_rate_mtx); + ret = random_adaptor_read_rate_cache; - mtx_unlock(&random_rate_mtx); + random_adaptor_read_rate_cache = 1; + + mtx_unlock(&random_read_rate_mtx); return (ret); } @@ -329,26 +281,25 @@ random_adaptor_read_rate(void) int random_adaptor_write(struct cdev *dev __unused, struct uio *uio, int flags __unused) { - int error; - struct random_adaptor_softc *ras; + int c, error = 0; + void *random_buf; KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__)); sx_slock(&random_adaptors_lock); - error = devfs_get_cdevpriv((void **)&ras); - if (error == 0) { - /* We used to allow this to insert userland entropy. - * We don't any more because (1) this so-called entropy - * is usually lousy and (b) its vaguely possible to - * mess with entropy harvesting by overdoing a write. - * Now we just ignore input like /dev/null does. - */ - /* XXX: FIX!! Now that RWFILE is gone, we need to get this back. - * ALSO: See devfs_get_cdevpriv(9) and friends for ways to build per-session nodes. - */ - uio->uio_resid = 0; - /* c = (random_adaptor->ra_write)(random_buf, c); */ + + random_buf = (void *)malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK); + + while (uio->uio_resid > 0) { + c = MIN((int)uio->uio_resid, PAGE_SIZE); + error = uiomove(random_buf, c, uio); + if (error) + break; + (random_adaptor->ra_write)(random_buf, c); } + + free(random_buf, M_ENTROPY); + sx_sunlock(&random_adaptors_lock); return (error); @@ -358,14 +309,9 @@ random_adaptor_write(struct cdev *dev __ int random_adaptor_poll(struct cdev *dev __unused, int events, struct thread *td __unused) { - struct random_adaptor_softc *ras; KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__)); - if (devfs_get_cdevpriv((void **)&ras) != 0) - return (events & - (POLLHUP|POLLIN|POLLRDNORM|POLLOUT|POLLWRNORM)); - sx_slock(&random_adaptors_lock); mtx_lock(&random_reseed_mtx); if (events & (POLLIN | POLLRDNORM)) { @@ -456,8 +402,7 @@ random_adaptors_init(void *unused __unus sx_init(&random_adaptors_lock, "random_adaptors"); - mtx_init(&random_rate_mtx, "read rate mutex", NULL, MTX_DEF); - mtx_init(&random_reseed_mtx, "read rate mutex", NULL, MTX_DEF); + mtx_init(&random_reseed_mtx, "reseed mutex", NULL, MTX_DEF); /* The dummy adaptor is not a module by itself, but part of the * randomdev module. @@ -475,7 +420,6 @@ random_adaptors_deinit(void *unused __un /* random_adaptor_deregister("dummy"); */ mtx_destroy(&random_reseed_mtx); - mtx_destroy(&random_rate_mtx); sx_destroy(&random_adaptors_lock); } @@ -515,7 +459,9 @@ random_adaptors_seed(void *unused __unus KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__)); sx_slock(&random_adaptors_lock); + mtx_lock(&random_reseed_mtx); random_adaptor->ra_reseed(); + mtx_unlock(&random_reseed_mtx); sx_sunlock(&random_adaptors_lock); arc4rand(NULL, 0, 1); Modified: projects/random_number_generator/sys/dev/random/random_adaptors.h ============================================================================== --- projects/random_number_generator/sys/dev/random/random_adaptors.h Mon Nov 25 21:17:14 2013 (r258597) +++ projects/random_number_generator/sys/dev/random/random_adaptors.h Mon Nov 25 21:30:45 2013 (r258598) @@ -61,10 +61,8 @@ extern struct random_adaptor randomdev_d void random_adaptor_register(const char *, struct random_adaptor *); void random_adaptor_deregister(const char *); -int random_adaptor_open(struct cdev *, int, int, struct thread *); int random_adaptor_read(struct cdev *, struct uio *, int); int random_adaptor_write(struct cdev *, struct uio *, int); -int random_adaptor_close(struct cdev *, int, int, struct thread *); int random_adaptor_poll(struct cdev *, int, struct thread *); int random_adaptor_read_rate(void); Modified: projects/random_number_generator/sys/dev/random/random_harvestq.c ============================================================================== --- projects/random_number_generator/sys/dev/random/random_harvestq.c Mon Nov 25 21:17:14 2013 (r258597) +++ projects/random_number_generator/sys/dev/random/random_harvestq.c Mon Nov 25 21:30:45 2013 (r258598) @@ -169,15 +169,6 @@ random_harvestq_flush(void) random_kthread_control = 1; while (random_kthread_control) pause("-", hz/10); - -#if 0 -#if defined(RANDOM_YARROW) - random_yarrow_reseed(); -#endif -#if defined(RANDOM_FORTUNA) - random_fortuna_reseed(); -#endif -#endif } /* ARGSUSED */ @@ -202,6 +193,49 @@ random_print_harvestmask(SYSCTL_HANDLER_ return (error); } +static const char *(random_source_descr[]) = { + "CACHED", + "ATTACH", + "KEYBOARD", + "MOUSE", + "NET_TUN", + "NET_ETHER", + "NET_NG", + "INTERRUPT", + "SWI", + "UMA_ALLOC", + "", /* "ENVIRONMENTAL_END" */ + "PURE_OCTEON", + "PURE_SAFE", + "PURE_GLXSB", + "PURE_UBSEC", *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***