From 4d87a031c0106945da094f3ea770ea9b4b5fcd6b Mon Sep 17 00:00:00 2001 From: Mark Murray Date: Sun, 10 Sep 2000 13:52:19 +0000 Subject: Large upgrade to the entropy device; mainly inspired by feedback from many folk. o The reseed process is now a kthread. With SMPng, kthreads are pre-emptive, so the annoying jerkiness of the mouse is gone. o The data structures are protected by mutexes now, not splfoo()/splx(). o The cryptographic routines are broken out into their own subroutines. this facilitates review, and possible replacement if that is ever found necessary. Thanks to: kris, green, peter, jasone, grog, jhb Forgotten to thank: You know who you are; no offense intended. --- sys/dev/random/hash.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 sys/dev/random/hash.h (limited to 'sys/dev/random/hash.h') diff --git a/sys/dev/random/hash.h b/sys/dev/random/hash.h new file mode 100644 index 000000000000..f210f13854a2 --- /dev/null +++ b/sys/dev/random/hash.h @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 2000 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$ + */ + +#define KEYSIZE 32 /* 32 bytes == 256 bits */ + +struct yarrowhash { /* Big! Make static! */ + BF_KEY hashkey; /* Data cycles through here */ + u_char ivec[8]; /* Blowfish Internal */ + u_char hash[KEYSIZE]; /* Repeatedly encrypted */ +}; + +struct yarrowkey { /* Big! Make static! */ + BF_KEY key; /* Key schedule */ + u_char ivec[8]; /* Blowfish Internal */ +}; + +void yarrow_hash_init(struct yarrowhash *, void *, size_t); +void yarrow_hash_iterate(struct yarrowhash *, void *, size_t); +void yarrow_hash_finish(struct yarrowhash *, void *); +void yarrow_encrypt_init(struct yarrowkey *, void *, size_t); +void yarrow_encrypt(struct yarrowkey *context, void *, void *, size_t); -- cgit v1.3 From 02c986ab5491cfc84666b5ce658dd7b3508b6b93 Mon Sep 17 00:00:00 2001 From: Mark Murray Date: Sat, 10 Mar 2001 12:51:55 +0000 Subject: Very large makeover of the /dev/random driver. o Separate the kernel stuff from the Yarrow algorithm. Yarrow is now well contained in one source file and one header. o Replace the Blowfish-based crypto routines with Rijndael-based ones. (Rijndael is the new AES algorithm). The huge improvement in Rijndael's key-agility over Blowfish means that this is an extremely dramatic improvement in speed, and makes a heck of a difference in its (lack of) CPU load. o Clean up the sysctl's. At BDE's prompting, I have gone back to static sysctls. o Bug fixes. The streamlining of the crypto stuff enabled me to find and fix some bugs. DES also found a bug in the reseed routine which is fixed. o Change the way reseeds clear "used" entropy. Previously, only the source(s) that caused a reseed were cleared. Now all sources in the relevant pool(s) are cleared. o Code tidy-up. Mostly to make it (nearly) 80-column compliant. --- sys/dev/random/harvest.c | 5 +- sys/dev/random/hash.c | 106 +++++++------ sys/dev/random/hash.h | 18 ++- sys/dev/random/randomdev.c | 335 ++++++++++++++++++++++++++++----------- sys/dev/random/randomdev.h | 83 ++++++++++ sys/dev/random/yarrow.c | 381 +++++++++++++-------------------------------- sys/dev/random/yarrow.h | 36 +---- 7 files changed, 505 insertions(+), 459 deletions(-) create mode 100644 sys/dev/random/randomdev.h (limited to 'sys/dev/random/hash.h') diff --git a/sys/dev/random/harvest.c b/sys/dev/random/harvest.c index 59495d712c72..c0c9a02d2cf7 100644 --- a/sys/dev/random/harvest.c +++ b/sys/dev/random/harvest.c @@ -38,10 +38,7 @@ #include -#include - -#include -#include +#include static u_int read_random_phony(void *, u_int); diff --git a/sys/dev/random/hash.c b/sys/dev/random/hash.c index 21c89e077da1..ed796f13d2ba 100644 --- a/sys/dev/random/hash.c +++ b/sys/dev/random/hash.c @@ -33,19 +33,17 @@ #include #include -#include +#include #include -/* initialise the hash by copying in some supplied data */ +/* initialise the hash by zeroing it */ void -yarrow_hash_init(struct yarrowhash *context, void *data, size_t size) +yarrow_hash_init(struct yarrowhash *context) { - size_t count; - - count = size > KEYSIZE ? KEYSIZE : size; - memset(context->hash, 0xff, KEYSIZE); - memcpy(context->hash, data, count); + rijndael_cipherInit(&context->cipher, MODE_CBC, NULL); + bzero(context->hash, KEYSIZE); + context->partial = 0; } /* Do a Davies-Meyer hash using a block cipher. @@ -55,65 +53,65 @@ yarrow_hash_init(struct yarrowhash *context, void *data, size_t size) void yarrow_hash_iterate(struct yarrowhash *context, void *data, size_t size) { - u_char keybuffer[KEYSIZE], temp[KEYSIZE]; - size_t count; - int iteration, last, i; + u_char temp[KEYSIZE]; + u_int i, j; - iteration = 0; - last = 0; - for (;;) { - if (size <= KEYSIZE) - last = 1; - count = size > KEYSIZE ? KEYSIZE : size; - memcpy(keybuffer, &((u_char *)data)[iteration], count); - memset(&keybuffer[KEYSIZE - count], 0xff, count); - BF_set_key(&context->hashkey, count, - &((u_char *)data)[iteration]); - BF_cbc_encrypt(context->hash, temp, KEYSIZE, &context->hashkey, - context->ivec, BF_ENCRYPT); - for (i = 0; i < KEYSIZE; i++) - context->hash[i] ^= temp[i]; - if (last) - break; - iteration += KEYSIZE; - size -= KEYSIZE; + for (i = 0; i < size; i++) { + context->accum[context->partial++] = ((u_char *)(data))[i]; + if (context->partial == (KEYSIZE - 1)) { + rijndael_makeKey(&context->hashkey, DIR_ENCRYPT, + KEYSIZE*8, context->accum); + rijndael_blockEncrypt(&context->cipher, + &context->hashkey, context->hash, + KEYSIZE*8, temp); + for (j = 0; j < KEYSIZE; j++) + context->hash[j] ^= temp[j]; + bzero(context->accum, KEYSIZE); + context->partial = 0; + } } } -/* Conclude by returning a pointer to the data */ +/* Conclude by returning the hash in the supplied /buf/ which must be + * KEYSIZE bytes long. Trailing data (less than KEYSIZE bytes) are + * not forgotten. + */ void yarrow_hash_finish(struct yarrowhash *context, void *buf) { - memcpy(buf, context->hash, sizeof(context->hash)); + u_char temp[KEYSIZE]; + int i; + + if (context->partial) { + rijndael_makeKey(&context->hashkey, DIR_ENCRYPT, + KEYSIZE*8, context->accum); + rijndael_blockEncrypt(&context->cipher, + &context->hashkey, context->hash, + KEYSIZE*8, temp); + for (i = 0; i < KEYSIZE; i++) + context->hash[i] ^= temp[i]; + } + memcpy(buf, context->hash, KEYSIZE); + bzero(context->hash, KEYSIZE); } -/* Initialise the encryption routine by setting up the key schedule */ +/* Initialise the encryption routine by setting up the key schedule + * from the supplied /key/ which must be KEYSIZE bytes of binary + * data. + */ void -yarrow_encrypt_init(struct yarrowkey *context, void *data, size_t size) +yarrow_encrypt_init(struct yarrowkey *context, void *data) { - size_t count; - - count = size > KEYSIZE ? KEYSIZE : size; - BF_set_key(&context->key, count, data); + rijndael_cipherInit(&context->cipher, MODE_CBC, NULL); + rijndael_makeKey(&context->key, DIR_ENCRYPT, KEYSIZE*8, data); } -/* Encrypt the supplied data using the key schedule preset in the context */ +/* Encrypt the supplied data using the key schedule preset in the context. + * KEYSIZE bytes are encrypted from /d_in/ to /d_out/. + */ void -yarrow_encrypt(struct yarrowkey *context, void *d_in, void *d_out, size_t size) +yarrow_encrypt(struct yarrowkey *context, void *d_in, void *d_out) { - size_t count; - int iteration, last; - - last = 0; - for (iteration = 0;; iteration += KEYSIZE) { - if (size <= KEYSIZE) - last = 1; - count = size > KEYSIZE ? KEYSIZE : size; - BF_cbc_encrypt(&((u_char *)d_in)[iteration], - &((u_char *)d_out)[iteration], count, &context->key, - context->ivec, BF_ENCRYPT); - if (last) - break; - size -= KEYSIZE; - } + rijndael_blockEncrypt(&context->cipher, &context->key, d_in, + KEYSIZE*8, d_out); } diff --git a/sys/dev/random/hash.h b/sys/dev/random/hash.h index f210f13854a2..99f0b4849b83 100644 --- a/sys/dev/random/hash.h +++ b/sys/dev/random/hash.h @@ -26,21 +26,23 @@ * $FreeBSD$ */ -#define KEYSIZE 32 /* 32 bytes == 256 bits */ +#define KEYSIZE 32 /* in bytes - 32 bytes == 256 bits */ struct yarrowhash { /* Big! Make static! */ - BF_KEY hashkey; /* Data cycles through here */ - u_char ivec[8]; /* Blowfish Internal */ + keyInstance hashkey; /* Data cycles through here */ + cipherInstance cipher; /* Rijndael internal */ u_char hash[KEYSIZE]; /* Repeatedly encrypted */ + u_char accum[KEYSIZE]; /* Accumulate partial chunks */ + u_int partial; /* Keep track of < KEYSIZE chunks */ }; struct yarrowkey { /* Big! Make static! */ - BF_KEY key; /* Key schedule */ - u_char ivec[8]; /* Blowfish Internal */ + keyInstance key; /* Key schedule */ + cipherInstance cipher; /* Rijndael internal */ }; -void yarrow_hash_init(struct yarrowhash *, void *, size_t); +void yarrow_hash_init(struct yarrowhash *); void yarrow_hash_iterate(struct yarrowhash *, void *, size_t); void yarrow_hash_finish(struct yarrowhash *, void *); -void yarrow_encrypt_init(struct yarrowkey *, void *, size_t); -void yarrow_encrypt(struct yarrowkey *context, void *, void *, size_t); +void yarrow_encrypt_init(struct yarrowkey *, void *); +void yarrow_encrypt(struct yarrowkey *context, void *, void *); diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c index 8358877c9d81..e30e9ae9da3b 100644 --- a/sys/dev/random/randomdev.c +++ b/sys/dev/random/randomdev.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -41,23 +42,23 @@ #include #include #include +#include + #include +#include #include -#include -#include -#include +#include -static d_open_t random_open; -static d_close_t random_close; -static d_read_t random_read; -static d_write_t random_write; -static d_ioctl_t random_ioctl; -static d_poll_t random_poll; +static d_open_t random_open; +static d_close_t random_close; +static d_read_t random_read; +static d_write_t random_write; +static d_ioctl_t random_ioctl; +static d_poll_t random_poll; #define CDEV_MAJOR 2 #define RANDOM_MINOR 3 -#define URANDOM_MINOR 4 static struct cdevsw random_cdevsw = { /* open */ random_open, @@ -76,13 +77,63 @@ static struct cdevsw random_cdevsw = { /* bmaj */ -1 }; +static void random_kthread(void *); +static void random_harvest_internal(u_int64_t, void *, u_int, u_int, u_int, enum esource); +static void random_write_internal(void *, u_int); + +/* Ring buffer holding harvested entropy */ +static struct harvestring { + volatile u_int head; + volatile u_int tail; + struct harvest data[HARVEST_RING_SIZE]; +} harvestring; + +static struct random_systat { + u_int seeded; /* 0 causes blocking 1 allows normal output */ + u_int burst; /* number of events to do before sleeping */ + struct selinfo rsel; /* For poll(2) */ +} random_systat; + +/* <0 to end the kthread, 0 to let it run */ +static int random_kthread_control = 0; + +static struct proc *random_kthread_proc; + /* For use with make_dev(9)/destroy_dev(9). */ -static dev_t random_dev; -static dev_t urandom_dev; /* XXX Temporary */ +static dev_t random_dev; +static dev_t urandom_dev; + +static int +random_check_boolean(SYSCTL_HANDLER_ARGS) +{ + if (oidp->oid_arg1 != NULL && *(u_int *)(oidp->oid_arg1) != 0) + *(u_int *)(oidp->oid_arg1) = 1; + return sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); +} -/* To stash the sysctl's until they are removed */ -static struct sysctl_oid *random_sysctl[12]; /* magic # is sysctl count */ -static int sysctlcount = 0; +RANDOM_CHECK_UINT(burst, 0, 20); + +SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, + 0, "Random Number Generator"); +SYSCTL_NODE(_kern_random, OID_AUTO, sys, CTLFLAG_RW, + 0, "Entropy Device Parameters"); +SYSCTL_PROC(_kern_random_sys, OID_AUTO, seeded, + CTLTYPE_INT|CTLFLAG_RW, &random_systat.seeded, 1, + random_check_boolean, "I", "Seeded State"); +SYSCTL_PROC(_kern_random_sys, OID_AUTO, burst, + CTLTYPE_INT|CTLFLAG_RW, &random_systat.burst, 20, + random_check_uint_burst, "I", "Harvest Burst Size"); +SYSCTL_NODE(_kern_random_sys, OID_AUTO, harvest, CTLFLAG_RW, + 0, "Entropy Sources"); +SYSCTL_PROC(_kern_random_sys_harvest, OID_AUTO, ethernet, + CTLTYPE_INT|CTLFLAG_RW, &harvest.ethernet, 0, + random_check_boolean, "I", "Harvest NIC entropy"); +SYSCTL_PROC(_kern_random_sys_harvest, OID_AUTO, point_to_point, + CTLTYPE_INT|CTLFLAG_RW, &harvest.point_to_point, 0, + random_check_boolean, "I", "Harvest serial net entropy"); +SYSCTL_PROC(_kern_random_sys_harvest, OID_AUTO, interrupt, + CTLTYPE_INT|CTLFLAG_RW, &harvest.interrupt, 0, + random_check_boolean, "I", "Harvest IRQ entropy"); static int random_open(dev_t dev, int flags, int fmt, struct proc *p) @@ -104,15 +155,16 @@ random_close(dev_t dev, int flags, int fmt, struct proc *p) static int random_read(dev_t dev, struct uio *uio, int flag) { - u_int c, ret; - int error = 0; - void *random_buf; + u_int c, ret; + int error = 0; + void *random_buf; - while (!random_state.seeded) { + while (!random_systat.seeded) { if (flag & IO_NDELAY) error = EWOULDBLOCK; else - error = tsleep(&random_state, PUSER|PCATCH, "rndblk", 0); + error = tsleep(&random_systat, PUSER|PCATCH, + "block", 0); if (error != 0) return error; } @@ -129,17 +181,18 @@ random_read(dev_t dev, struct uio *uio, int flag) static int random_write(dev_t dev, struct uio *uio, int flag) { - u_int c; - int error = 0; - void *random_buf; + u_int c; + int error; + void *random_buf; + error = 0; random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); while (uio->uio_resid > 0) { c = min(uio->uio_resid, PAGE_SIZE); error = uiomove(random_buf, c, uio); if (error) break; - write_random(random_buf, c); + random_write_internal(random_buf, c); } free(random_buf, M_TEMP); return error; @@ -154,14 +207,14 @@ random_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) static int random_poll(dev_t dev, int events, struct proc *p) { - int revents; + int revents; revents = 0; if (events & (POLLIN | POLLRDNORM)) { - if (random_state.seeded) + if (random_systat.seeded) revents = events & (POLLIN | POLLRDNORM); else - selrecord(p, &random_state.rsel); + selrecord(p, &random_systat.rsel); } return revents; } @@ -169,84 +222,58 @@ random_poll(dev_t dev, int events, struct proc *p) static int random_modevent(module_t mod, int type, void *data) { - struct sysctl_oid *node_base, *node1, *node2; - int error, i; + int error; switch(type) { case MOD_LOAD: - error = random_init(); - if (error != 0) - return error; + random_init(); + + /* This can be turned off by the very paranoid + * a reseed will turn it back on. + */ + random_systat.seeded = 1; - random_sysctl[sysctlcount++] = node_base = - SYSCTL_ADD_NODE(NULL, SYSCTL_STATIC_CHILDREN(_kern), - OID_AUTO, "random", CTLFLAG_RW, 0, - "Random Number Generator"); - random_sysctl[sysctlcount++] = node1 = - SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(node_base), - OID_AUTO, "sys", CTLFLAG_RW, 0, - "Entropy Device Parameters"); - random_sysctl[sysctlcount++] = - SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(node1), - OID_AUTO, "seeded", CTLFLAG_RW, - &random_state.seeded, 0, "Seeded State"); - random_sysctl[sysctlcount++] = - SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(node1), - OID_AUTO, "harvest_ethernet", CTLFLAG_RW, - &harvest.ethernet, 0, "Harvest NIC entropy"); - random_sysctl[sysctlcount++] = - SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(node1), - OID_AUTO, "harvest_point_to_point", CTLFLAG_RW, - &harvest.point_to_point, 0, "Harvest serial net entropy"); - random_sysctl[sysctlcount++] = - SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(node1), - OID_AUTO, "harvest_interrupt", CTLFLAG_RW, - &harvest.interrupt, 0, "Harvest IRQ entropy"); - random_sysctl[sysctlcount++] = node2 = - SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(node_base), - OID_AUTO, "yarrow", CTLFLAG_RW, 0, - "Yarrow Parameters"); - random_sysctl[sysctlcount++] = - SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(node2), - OID_AUTO, "gengateinterval", CTLFLAG_RW, - &random_state.gengateinterval, 0, - "Generator Gate Interval"); - random_sysctl[sysctlcount++] = - SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(node2), - OID_AUTO, "bins", CTLFLAG_RW, - &random_state.bins, 0, - "Execution time tuner"); - random_sysctl[sysctlcount++] = - SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(node2), - OID_AUTO, "fastthresh", CTLFLAG_RW, - &random_state.pool[0].thresh, 0, - "Fast pool reseed threshhold"); - random_sysctl[sysctlcount++] = - SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(node2), - OID_AUTO, "slowthresh", CTLFLAG_RW, - &random_state.pool[1].thresh, 0, - "Slow pool reseed threshhold"); - random_sysctl[sysctlcount++] = - SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(node2), - OID_AUTO, "slowoverthresh", CTLFLAG_RW, - &random_state.slowoverthresh, 0, - "Slow pool over-threshhold reseed"); + /* Number of envents to process off the harvest + * queue before giving it a break and sleeping + */ + random_systat.burst = 20; + + /* Initialise the harvest ringbuffer */ + harvestring.head = 0; + harvestring.tail = 0; if (bootverbose) printf("random: \n"); random_dev = make_dev(&random_cdevsw, RANDOM_MINOR, UID_ROOT, GID_WHEEL, 0666, "random"); - urandom_dev = make_dev(&random_cdevsw, URANDOM_MINOR, UID_ROOT, - GID_WHEEL, 0666, "urandom"); /* XXX Temporary */ + urandom_dev = make_dev_alias(random_dev, "urandom"); + + /* Start the hash/reseed thread */ + error = kthread_create(random_kthread, NULL, + &random_kthread_proc, RFHIGHPID, "random"); + if (error != 0) + return error; + + /* Register the randomness harvesting routine */ + random_init_harvester(random_harvest_internal, + read_random_real); + return 0; case MOD_UNLOAD: + /* Deregister the randomness harvesting routine */ + random_deinit_harvester(); + + /* Command the hash/reseed thread to end and + * wait for it to finish + */ + random_kthread_control = -1; + tsleep((void *)&random_kthread_control, PUSER, "term", 0); + random_deinit(); + destroy_dev(random_dev); - destroy_dev(urandom_dev); /* XXX Temporary */ - for (i = sysctlcount - 1; i >= 0; i--) - if (sysctl_remove_oid(random_sysctl[i], 1, 0) == EINVAL) - panic("random: removing sysctl"); + destroy_dev(urandom_dev); return 0; case MOD_SHUTDOWN: @@ -258,3 +285,129 @@ random_modevent(module_t mod, int type, void *data) } DEV_MODULE(random, random_modevent, NULL); + +static void +random_kthread(void *arg /* NOTUSED */) +{ + struct harvest *event; + int newtail, burst; + + /* Drain the harvest queue (in 'burst' size chunks, + * if 'burst' > 0. If 'burst' == 0, then completely + * drain the queue. + */ + for (burst = 0; ; burst++) { + + if ((harvestring.tail == harvestring.head) || + (random_systat.burst && burst == random_systat.burst)) { + tsleep(&harvestring, PUSER, "sleep", hz/10); + burst = 0; + + } + else { + + /* Suck a harvested entropy event out of the queue and + * hand it to the event processor + */ + + newtail = (harvestring.tail + 1) & HARVEST_RING_MASK; + event = &harvestring.data[harvestring.tail]; + + /* Bump the ring counter. This action is assumed + * to be atomic. + */ + harvestring.tail = newtail; + + random_process_event(event); + + } + + /* Is the thread scheduled for a shutdown? */ + if (random_kthread_control != 0) { +#ifdef DEBUG + mtx_lock(&Giant); + printf("Random kthread setting terminate\n"); + mtx_unlock(&Giant); +#endif + random_set_wakeup_exit(&random_kthread_control); + /* NOTREACHED */ + break; + } + + } + +} + +/* Entropy harvesting routine. This is supposed to be fast; do + * not do anything slow in here! + */ +static void +random_harvest_internal(u_int64_t somecounter, void *entropy, u_int count, + u_int bits, u_int frac, enum esource origin) +{ + struct harvest *harvest; + int newhead; + + newhead = (harvestring.head + 1) & HARVEST_RING_MASK; + + if (newhead != harvestring.tail) { + + /* Add the harvested data to the ring buffer */ + + harvest = &harvestring.data[harvestring.head]; + + /* Stuff the harvested data into the ring */ + harvest->somecounter = somecounter; + count = count > HARVESTSIZE ? HARVESTSIZE : count; + memcpy(harvest->entropy, entropy, count); + harvest->size = count; + harvest->bits = bits; + harvest->frac = frac; + harvest->source = origin < ENTROPYSOURCE ? origin : 0; + + /* Bump the ring counter. This action is assumed + * to be atomic. + */ + harvestring.head = newhead; + + } + +} + +static void +random_write_internal(void *buf, u_int count) +{ + u_int i; + + /* Break the input up into HARVESTSIZE chunks. + * The writer has too much control here, so "estimate" the + * the entropy as zero. + */ + for (i = 0; i < count; i += HARVESTSIZE) { + random_harvest_internal(get_cyclecount(), (char *)buf + i, + HARVESTSIZE, 0, 0, RANDOM_WRITE); + } + + /* Maybe the loop iterated at least once */ + if (i > count) + i -= HARVESTSIZE; + + /* Get the last bytes even if the input length is not + * a multiple of HARVESTSIZE. + */ + count %= HARVESTSIZE; + if (count) { + random_harvest_internal(get_cyclecount(), (char *)buf + i, + count, 0, 0, RANDOM_WRITE); + } +} + +void +random_unblock(void) +{ + if (!random_systat.seeded) { + random_systat.seeded = 1; + selwakeup(&random_systat.rsel); + wakeup(&random_systat); + } +} diff --git a/sys/dev/random/randomdev.h b/sys/dev/random/randomdev.h new file mode 100644 index 000000000000..dc6a67366c94 --- /dev/null +++ b/sys/dev/random/randomdev.h @@ -0,0 +1,83 @@ +/*- + * Copyright (c) 2001 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$ + */ + +/* This header contains only those definitions that are global + * and non algorithm-specific for the entropy processor + */ + +/* #define ENTROPYSOURCE nn entropy sources (actually classes) + * This is properly defined in + * an enum in sys/random.h + */ + +/* Cryptographic block size in bits */ +#define BLOCKSIZE 256 + +/* The ring size _MUST_ be a power of 2 */ +#define HARVEST_RING_SIZE 1024 /* harvest ring buffer size */ +#define HARVEST_RING_MASK (HARVEST_RING_SIZE - 1) + +#define HARVESTSIZE 16 /* max size of each harvested entropy unit */ + +SYSCTL_DECL(_kern_random); + +/* These are used to queue harvested packets of entropy. The entropy + * buffer size is pretty arbitrary. + */ +struct harvest { + u_int64_t somecounter; /* fast counter for clock jitter */ + u_char entropy[HARVESTSIZE]; /* the harvested entropy */ + u_int size, bits, frac; /* stats about the entropy */ + enum esource source; /* stats about the entropy */ +}; + +void random_init(void); +void random_deinit(void); +void random_init_harvester(void (*)(u_int64_t, void *, u_int, u_int, u_int, enum esource), u_int (*)(void *, u_int)); +void random_deinit_harvester(void); +void random_set_wakeup_exit(void *); +void random_process_event(struct harvest *event); +void random_reseed(void); +void random_unblock(void); + +u_int read_random_real(void *, u_int); + +/* If this was c++, this would be a template */ +#define RANDOM_CHECK_UINT(name, min, max) \ +static int \ +random_check_uint_##name##(SYSCTL_HANDLER_ARGS) \ +{ \ + if (oidp->oid_arg1 != NULL) { \ + if (*(u_int *)(oidp->oid_arg1) < min) \ + *(u_int *)(oidp->oid_arg1) = min; \ + else if (*(u_int *)(oidp->oid_arg1) > max) \ + *(u_int *)(oidp->oid_arg1) = max; \ + } \ + return sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, \ + req); \ +} diff --git a/sys/dev/random/yarrow.c b/sys/dev/random/yarrow.c index 6313587f23d6..542bece74af7 100644 --- a/sys/dev/random/yarrow.c +++ b/sys/dev/random/yarrow.c @@ -29,229 +29,128 @@ #include #include #include -#include #include #include #include #include +#include #include -#include -#include -#include - -#include +#include #include +#include #include /* #define DEBUG */ -static void generator_gate(void); -static void reseed(int); -static void random_harvest_internal(u_int64_t, void *, u_int, u_int, u_int, enum esource); +RANDOM_CHECK_UINT(gengateinterval, 4, 64); +RANDOM_CHECK_UINT(bins, 2, 16); +RANDOM_CHECK_UINT(fastthresh, BLOCKSIZE/4, BLOCKSIZE); +RANDOM_CHECK_UINT(slowthresh, BLOCKSIZE/4, BLOCKSIZE); +RANDOM_CHECK_UINT(slowoverthresh, 1, 5); + +SYSCTL_NODE(_kern_random, OID_AUTO, yarrow, CTLFLAG_RW, 0, "Yarrow Parameters"); +SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, gengateinterval, + CTLTYPE_INT|CTLFLAG_RW, &random_state.gengateinterval, 10, + random_check_uint_gengateinterval, "I", "Generator Gate Interval"); +SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, bins, + CTLTYPE_INT|CTLFLAG_RW, &random_state.bins, 10, + random_check_uint_bins, "I", "Execution time tuner"); +SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, fastthresh, + CTLTYPE_INT|CTLFLAG_RW, &random_state.pool[0].thresh, (3*BLOCKSIZE)/4, + random_check_uint_fastthresh, "I", "Fast reseed threshold"); +SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, slowthresh, + CTLTYPE_INT|CTLFLAG_RW, &random_state.pool[1].thresh, BLOCKSIZE, + random_check_uint_slowthresh, "I", "Slow reseed threshold"); +SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, slowoverthresh, + CTLTYPE_INT|CTLFLAG_RW, &random_state.slowoverthresh, 2, + random_check_uint_slowoverthresh, "I", "Slow over-threshold reseed"); -static void random_kthread(void *); +static void generator_gate(void); +static void reseed(u_int); /* Structure holding the entropy state */ struct random_state random_state; -/* These are used to queue harvested packets of entropy. The entropy - * buffer size is pretty arbitrary. - */ -struct harvest { - u_int64_t somecounter; /* fast counter for clock jitter */ - u_char entropy[HARVESTSIZE]; /* the harvested entropy */ - u_int size, bits, frac; /* stats about the entropy */ - enum esource source; /* stats about the entropy */ -}; - -/* Ring buffer holding harvested entropy */ -static struct harvestring { - volatile int head; - volatile int tail; - struct harvest data[HARVEST_RING_SIZE]; -} harvestring; - /* The reseed thread mutex */ static struct mtx random_reseed_mtx; -/* <0 to end the kthread, 0 to let it run */ -static int random_kthread_control = 0; - -static struct proc *random_kthread_proc; - -static void -random_kthread(void *arg /* NOTUSED */) +/* Process a single stochastic event off the harvest queue */ +void +random_process_event(struct harvest *event) { - int pl, src, overthreshhold[2], newtail; - struct harvest *event; + u_int pl, src, overthreshhold[2]; struct source *source; -#ifdef DEBUG - mtx_lock(&Giant); - printf("OWNERSHIP Giant == %d sched_lock == %d\n", - mtx_owned(&Giant), mtx_owned(&sched_lock)); - mtx_unlock(&Giant); -#endif - - for (pl = 0; pl < 2; pl++) - yarrow_hash_init(&random_state.pool[pl].hash, NULL, 0); - - for (;;) { - - if (harvestring.tail == harvestring.head) - tsleep(&harvestring, PUSER, "rndslp", hz/10); - - else { - - /* Suck the harvested entropy out of the queue and hash - * it into the appropriate pool. - */ - - newtail = (harvestring.tail + 1) & HARVEST_RING_MASK; - event = &harvestring.data[harvestring.tail]; - - /* Bump the ring counter. This action is assumed - * to be atomic. - */ - harvestring.tail = newtail; - - pl = random_state.which = !random_state.which; - - source = &random_state.pool[pl].source[event->source]; - yarrow_hash_iterate(&random_state.pool[pl].hash, - event->entropy, sizeof(event->entropy)); - yarrow_hash_iterate(&random_state.pool[pl].hash, - &event->somecounter, sizeof(event->somecounter)); - source->frac += event->frac; - source->bits += event->bits + source->frac/1024; - source->frac %= 1024; - - /* Count the over-threshold sources in each pool */ - for (pl = 0; pl < 2; pl++) { - overthreshhold[pl] = 0; - for (src = 0; src < ENTROPYSOURCE; src++) { - if (random_state.pool[pl].source[src].bits - > random_state.pool[pl].thresh) - overthreshhold[pl]++; - } - } - - /* if any fast source over threshhold, reseed */ - if (overthreshhold[FAST]) - reseed(FAST); - - /* if enough slow sources are over threshhold, reseed */ - if (overthreshhold[SLOW] >= random_state.slowoverthresh) - reseed(SLOW); - + /* Unpack the event into the appropriate source accumulator */ + pl = random_state.which; + source = &random_state.pool[pl].source[event->source]; + yarrow_hash_iterate(&random_state.pool[pl].hash, event->entropy, + sizeof(event->entropy)); + yarrow_hash_iterate(&random_state.pool[pl].hash, &event->somecounter, + sizeof(event->somecounter)); + source->frac += event->frac; + source->bits += event->bits + source->frac/1024; + source->frac %= 1024; + + /* Count the over-threshold sources in each pool */ + for (pl = 0; pl < 2; pl++) { + overthreshhold[pl] = 0; + for (src = 0; src < ENTROPYSOURCE; src++) { + if (random_state.pool[pl].source[src].bits + > random_state.pool[pl].thresh) + overthreshhold[pl]++; } + } - /* Is the thread scheduled for a shutdown? */ - if (random_kthread_control != 0) { -#ifdef DEBUG - mtx_lock(&Giant); - printf("Random kthread setting terminate\n"); - mtx_unlock(&Giant); -#endif - random_set_wakeup_exit(&random_kthread_control); - /* NOTREACHED */ - break; - } + /* if any fast source over threshhold, reseed */ + if (overthreshhold[FAST]) + reseed(FAST); - } + /* if enough slow sources are over threshhold, reseed */ + if (overthreshhold[SLOW] >= random_state.slowoverthresh) + reseed(SLOW); + /* Invert the fast/slow pool selector bit */ + random_state.which = !random_state.which; } -int +void random_init(void) { - int error; - -#ifdef DEBUG - mtx_lock(&Giant); - printf("Random initialise\n"); - mtx_unlock(&Giant); -#endif - - /* This can be turned off by the very paranoid - * a reseed will turn it back on. - */ - random_state.seeded = 1; + int i; /* Yarrow parameters. Do not adjust these unless you have * have a very good clue about what they do! */ random_state.gengateinterval = 10; random_state.bins = 10; - random_state.pool[0].thresh = 100; - random_state.pool[1].thresh = 160; + random_state.pool[0].thresh = (3*BLOCKSIZE)/4; + random_state.pool[1].thresh = BLOCKSIZE; random_state.slowoverthresh = 2; random_state.which = FAST; - mtx_init(&random_reseed_mtx, "random reseed", MTX_DEF); - - harvestring.head = 0; - harvestring.tail = 0; - - /* Start the hash/reseed thread */ - error = kthread_create(random_kthread, NULL, - &random_kthread_proc, RFHIGHPID, "random"); - if (error != 0) - return error; + /* Initialise the fast and slow entropy pools */ + for (i = 0; i < 2; i++) + yarrow_hash_init(&random_state.pool[i].hash); - /* Register the randomness harvesting routine */ - random_init_harvester(random_harvest_internal, read_random_real); + /* Clear the counter */ + for (i = 0; i < 4; i++) + random_state.counter[i] = 0; -#ifdef DEBUG - mtx_lock(&Giant); - printf("Random initialise finish\n"); - mtx_unlock(&Giant); -#endif - - return 0; + /* Set up a lock for the reseed process */ + mtx_init(&random_reseed_mtx, "random reseed", MTX_DEF); } void random_deinit(void) { -#ifdef DEBUG - mtx_lock(&Giant); - printf("Random deinitialise\n"); - mtx_unlock(&Giant); -#endif - - /* Deregister the randomness harvesting routine */ - random_deinit_harvester(); - -#ifdef DEBUG - mtx_lock(&Giant); - printf("Random deinitialise waiting for thread to terminate\n"); - mtx_unlock(&Giant); -#endif - - /* Command the hash/reseed thread to end and wait for it to finish */ - random_kthread_control = -1; - tsleep((void *)&random_kthread_control, PUSER, "rndend", 0); - -#ifdef DEBUG - mtx_lock(&Giant); - printf("Random deinitialise removing mutexes\n"); - mtx_unlock(&Giant); -#endif - mtx_destroy(&random_reseed_mtx); - -#ifdef DEBUG - mtx_lock(&Giant); - printf("Random deinitialise finish\n"); - mtx_unlock(&Giant); -#endif } static void -reseed(int fastslow) +reseed(u_int fastslow) { /* Interrupt-context stack is a limited resource; make large * structures static. @@ -260,7 +159,7 @@ reseed(int fastslow) static struct yarrowhash context; u_char hash[KEYSIZE]; /* h' */ u_char temp[KEYSIZE]; - int i, j; + u_int i, j; #ifdef DEBUG mtx_lock(&Giant); @@ -273,14 +172,15 @@ reseed(int fastslow) /* 1. Hash the accumulated entropy into v[0] */ - yarrow_hash_init(&context, NULL, 0); + yarrow_hash_init(&context); /* Feed the slow pool hash in if slow */ if (fastslow == SLOW) yarrow_hash_iterate(&context, - &random_state.pool[SLOW].hash, sizeof(struct yarrowhash)); - + &random_state.pool[SLOW].hash, + sizeof(struct yarrowhash)); yarrow_hash_iterate(&context, &random_state.pool[FAST].hash, sizeof(struct yarrowhash)); + yarrow_hash_finish(&context, v[0]); /* 2. Compute hash values for all v. _Supposed_ to be computationally * intensive. @@ -289,13 +189,13 @@ reseed(int fastslow) if (random_state.bins > TIMEBIN) random_state.bins = TIMEBIN; for (i = 1; i < random_state.bins; i++) { - yarrow_hash_init(&context, NULL, 0); - /* v[i] #= h(v[i-1]) */ + yarrow_hash_init(&context); + /* v[i] #= h(v[i - 1]) */ yarrow_hash_iterate(&context, v[i - 1], KEYSIZE); /* v[i] #= h(v[0]) */ yarrow_hash_iterate(&context, v[0], KEYSIZE); /* v[i] #= h(i) */ - yarrow_hash_iterate(&context, &i, sizeof(int)); + yarrow_hash_iterate(&context, &i, sizeof(u_int)); /* Return the hashval */ yarrow_hash_finish(&context, v[i]); } @@ -304,29 +204,26 @@ reseed(int fastslow) * it is not being ignored! */ - yarrow_hash_init(&context, NULL, 0); + yarrow_hash_init(&context); yarrow_hash_iterate(&context, &random_state.key, KEYSIZE); for (i = 1; i < random_state.bins; i++) yarrow_hash_iterate(&context, &v[i], KEYSIZE); yarrow_hash_finish(&context, temp); - yarrow_encrypt_init(&random_state.key, temp, KEYSIZE); + yarrow_encrypt_init(&random_state.key, temp); /* 4. Recompute the counter */ - random_state.counter = 0; - yarrow_encrypt(&random_state.key, &random_state.counter, temp, - sizeof(random_state.counter)); - memcpy(&random_state.counter, temp, random_state.counter); + for (i = 0; i < 4; i++) + random_state.counter[i] = 0; + yarrow_encrypt(&random_state.key, random_state.counter, temp); + memcpy(random_state.counter, temp, sizeof(random_state.counter)); /* 5. Reset entropy estimate accumulators to zero */ for (i = 0; i <= fastslow; i++) { for (j = 0; j < ENTROPYSOURCE; j++) { - if (random_state.pool[i].source[j].bits > - random_state.pool[i].thresh) { - random_state.pool[i].source[j].bits = 0; - random_state.pool[i].source[j].frac = 0; - } + random_state.pool[i].source[j].bits = 0; + random_state.pool[i].source[j].frac = 0; } } @@ -348,14 +245,13 @@ reseed(int fastslow) mtx_unlock(&Giant); #endif - if (!random_state.seeded) { - random_state.seeded = 1; - selwakeup(&random_state.rsel); - wakeup(&random_state); - } - + /* Unblock the device if it was blocked due to being unseeded */ + random_unblock(); } +/* Internal function to do return processed entropy from the + * Yarrow PRNG + */ u_int read_random_real(void *buf, u_int count) { @@ -376,12 +272,13 @@ read_random_real(void *buf, u_int count) if (count >= sizeof(random_state.counter)) { retval = 0; for (i = 0; i < count; i += sizeof(random_state.counter)) { - random_state.counter++; - yarrow_encrypt(&random_state.key, &random_state.counter, - &genval, sizeof(random_state.counter)); + random_state.counter[0]++; + yarrow_encrypt(&random_state.key, random_state.counter, + &genval); memcpy((char *)buf + i, &genval, sizeof(random_state.counter)); - if (++random_state.outputblocks >= random_state.gengateinterval) { + if (++random_state.outputblocks >= + random_state.gengateinterval) { generator_gate(); random_state.outputblocks = 0; } @@ -390,12 +287,13 @@ read_random_real(void *buf, u_int count) } else { if (!cur) { - random_state.counter++; - yarrow_encrypt(&random_state.key, &random_state.counter, - &genval, sizeof(random_state.counter)); + random_state.counter[0]++; + yarrow_encrypt(&random_state.key, random_state.counter, + &genval); memcpy(buf, &genval, count); cur = sizeof(random_state.counter) - count; - if (++random_state.outputblocks >= random_state.gengateinterval) { + if (++random_state.outputblocks >= + random_state.gengateinterval) { generator_gate(); random_state.outputblocks = 0; } @@ -414,38 +312,10 @@ read_random_real(void *buf, u_int count) return retval; } -void -write_random(void *buf, u_int count) -{ - u_int i; - - /* Break the input up into HARVESTSIZE chunks. - * The writer has too much control here, so "estimate" the - * the entropy as zero. - */ - for (i = 0; i < count; i += HARVESTSIZE) { - random_harvest_internal(get_cyclecount(), (char *)buf + i, - HARVESTSIZE, 0, 0, RANDOM_WRITE); - } - - /* Maybe the loop iterated at least once */ - if (i > count) - i -= HARVESTSIZE; - - /* Get the last bytes even if the input length is not - * a multiple of HARVESTSIZE. - */ - count %= HARVESTSIZE; - if (count) { - random_harvest_internal(get_cyclecount(), (char *)buf + i, - count, 0, 0, RANDOM_WRITE); - } -} - static void generator_gate(void) { - int i; + u_int i; u_char temp[KEYSIZE]; #ifdef DEBUG @@ -455,12 +325,12 @@ generator_gate(void) #endif for (i = 0; i < KEYSIZE; i += sizeof(random_state.counter)) { - random_state.counter++; - yarrow_encrypt(&random_state.key, &random_state.counter, - &(temp[i]), sizeof(random_state.counter)); + random_state.counter[0]++; + yarrow_encrypt(&random_state.key, random_state.counter, + &(temp[i])); } - yarrow_encrypt_init(&random_state.key, temp, KEYSIZE); + yarrow_encrypt_init(&random_state.key, temp); memset((void *)temp, 0, KEYSIZE); #ifdef DEBUG @@ -470,43 +340,6 @@ generator_gate(void) #endif } -/* Entropy harvesting routine. This is supposed to be fast; do - * not do anything slow in here! - */ - -static void -random_harvest_internal(u_int64_t somecounter, void *entropy, u_int count, - u_int bits, u_int frac, enum esource origin) -{ - struct harvest *harvest; - int newhead; - - newhead = (harvestring.head + 1) & HARVEST_RING_MASK; - - if (newhead != harvestring.tail) { - - /* Add the harvested data to the ring buffer */ - - harvest = &harvestring.data[harvestring.head]; - - /* Stuff the harvested data into the ring */ - harvest->somecounter = somecounter; - count = count > HARVESTSIZE ? HARVESTSIZE : count; - memcpy(harvest->entropy, entropy, count); - harvest->size = count; - harvest->bits = bits; - harvest->frac = frac; - harvest->source = origin < ENTROPYSOURCE ? origin : 0; - - /* Bump the ring counter. This action is assumed - * to be atomic. - */ - harvestring.head = newhead; - - } - -} - /* Helper routine to perform explicit reseeds */ void random_reseed(void) diff --git a/sys/dev/random/yarrow.h b/sys/dev/random/yarrow.h index d605356cf3b9..7c603c778079 100644 --- a/sys/dev/random/yarrow.h +++ b/sys/dev/random/yarrow.h @@ -26,42 +26,25 @@ * $FreeBSD$ */ -/* #define ENTROPYSOURCE nn entropy sources (actually classes) - * This is properly defined in - * an enum in sys/random.h +/* This contains Yarrow-specific declarations. + * See http://www.counterpane.com/yarrow.html */ -/* The ring size _MUST_ be a power of 2 */ -#define HARVEST_RING_SIZE 1024 /* harvest ring buffer size */ -#define HARVEST_RING_MASK (HARVEST_RING_SIZE - 1) - #define TIMEBIN 16 /* max value for Pt/t */ -#define HARVESTSIZE 16 /* max size of each harvested entropy unit */ - #define FAST 0 #define SLOW 1 -int random_init(void); -void random_deinit(void); -void random_init_harvester(void (*)(u_int64_t, void *, u_int, u_int, u_int, enum esource), u_int (*)(void *, u_int)); -void random_deinit_harvester(void); -void random_set_wakeup_exit(void *); - -void random_reseed(void); - -u_int read_random_real(void *, u_int); -void write_random(void *, u_int); - /* This is the beastie that needs protecting. It contains all of the * state that we are excited about. + * Exactly one will be instantiated. */ struct random_state { - u_int64_t counter; /* C */ + u_int64_t counter[4]; /* C - 256 bits */ struct yarrowkey key; /* K */ - int gengateinterval; /* Pg */ - int bins; /* Pt/t */ - int outputblocks; /* count output blocks for gates */ + u_int gengateinterval; /* Pg */ + u_int bins; /* Pt/t */ + u_int outputblocks; /* count output blocks for gates */ u_int slowoverthresh; /* slow pool overthreshhold reseed count */ struct pool { struct source { @@ -72,10 +55,7 @@ struct random_state { u_int thresh; /* pool reseed threshhold */ struct yarrowhash hash; /* accumulated entropy */ } pool[2]; /* pool[0] is fast, pool[1] is slow */ - int which; /* toggle - shows the current insertion pool */ - int seeded; /* 0 causes blocking 1 allows normal output */ - struct selinfo rsel; /* For poll(2) */ - u_char raw[HARVESTSIZE];/* Raw buffer for checking */ + u_int which; /* toggle - sets the current insertion pool */ }; extern struct random_state random_state; -- cgit v1.3 From e119960112f35b3ec1179e262cccde05b59a0309 Mon Sep 17 00:00:00 2001 From: Mark Murray Date: Sun, 3 Mar 2002 19:44:22 +0000 Subject: Massive lint-inspired cleanup. Remove unneeded includes. Deal with unused function arguments. Resolve a boatload of signed/unsigned imcompatabilities. Etc. --- sys/dev/random/harvest.c | 22 +++++++------- sys/dev/random/hash.c | 11 +++---- sys/dev/random/hash.h | 2 +- sys/dev/random/randomdev.c | 71 ++++++++++++++++++++++++++-------------------- sys/dev/random/randomdev.h | 12 ++++---- sys/dev/random/yarrow.c | 36 +++++++++++------------ sys/sys/random.h | 15 +++++++--- 7 files changed, 95 insertions(+), 74 deletions(-) (limited to 'sys/dev/random/hash.h') diff --git a/sys/dev/random/harvest.c b/sys/dev/random/harvest.c index e9ac7f9220d6..1e2275d60744 100644 --- a/sys/dev/random/harvest.c +++ b/sys/dev/random/harvest.c @@ -42,7 +42,7 @@ #include -static u_int read_random_phony(void *, u_int); +static int read_random_phony(void *, int); /* Structure holding the desired entropy sources */ struct harvest_select harvest = { 0, 0, 0 }; @@ -52,12 +52,12 @@ struct harvest_select harvest = { 0, 0, 0 }; */ static void (*reap_func)(u_int64_t, void *, u_int, u_int, u_int, enum esource) = NULL; -static u_int (*read_func)(void *, u_int) = read_random_phony; +static int (*read_func)(void *, int) = read_random_phony; /* Initialise the harvester at load time */ void random_init_harvester(void (*reaper)(u_int64_t, void *, u_int, u_int, u_int, - enum esource), u_int (*reader)(void *, u_int)) + enum esource), int (*reader)(void *, int)) { reap_func = reaper; read_func = reader; @@ -86,8 +86,8 @@ random_harvest(void *entropy, u_int count, u_int bits, u_int frac, } /* Userland-visible version of read_random */ -u_int -read_random(void *buf, u_int count) +int +read_random(void *buf, int count) { return (*read_func)(buf, count); } @@ -96,8 +96,8 @@ read_random(void *buf, u_int count) * provide _some_ kind of randomness. This should only be used * inside other RNG's, like arc4random(9). */ -static u_int -read_random_phony(void *buf, u_int count) +static int +read_random_phony(void *buf, int count) { u_long randval; int size, i; @@ -110,10 +110,12 @@ read_random_phony(void *buf, u_int count) srandom((u_long)get_cyclecount()); /* Fill buf[] with random(9) output */ - for (i = 0; i < count; i+= sizeof(u_long)) { + for (i = 0; i < count; i+= (size_t)sizeof(u_long)) { randval = random(); - size = (count - i) < sizeof(u_long) ? (count - i) : sizeof(u_long); - memcpy(&((char *)buf)[i], &randval, size); + size = (count - i) < (int)sizeof(u_long) + ? (count - i) + : sizeof(u_long); + memcpy(&((char *)buf)[i], &randval, (size_t)size); } return count; diff --git a/sys/dev/random/hash.c b/sys/dev/random/hash.c index ed796f13d2ba..a9246c34db7c 100644 --- a/sys/dev/random/hash.c +++ b/sys/dev/random/hash.c @@ -28,10 +28,6 @@ #include #include -#include -#include -#include -#include #include @@ -55,9 +51,14 @@ yarrow_hash_iterate(struct yarrowhash *context, void *data, size_t size) { u_char temp[KEYSIZE]; u_int i, j; + union { + void *pv; + char *pc; + } trans; + trans.pv = data; for (i = 0; i < size; i++) { - context->accum[context->partial++] = ((u_char *)(data))[i]; + context->accum[context->partial++] = trans.pc[i]; if (context->partial == (KEYSIZE - 1)) { rijndael_makeKey(&context->hashkey, DIR_ENCRYPT, KEYSIZE*8, context->accum); diff --git a/sys/dev/random/hash.h b/sys/dev/random/hash.h index 99f0b4849b83..5a308210d690 100644 --- a/sys/dev/random/hash.h +++ b/sys/dev/random/hash.h @@ -32,7 +32,7 @@ struct yarrowhash { /* Big! Make static! */ keyInstance hashkey; /* Data cycles through here */ cipherInstance cipher; /* Rijndael internal */ u_char hash[KEYSIZE]; /* Repeatedly encrypted */ - u_char accum[KEYSIZE]; /* Accumulate partial chunks */ + char accum[KEYSIZE]; /* Accumulate partial chunks */ u_int partial; /* Keep track of < KEYSIZE chunks */ }; diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c index fe73b0fe7551..8587200a727e 100644 --- a/sys/dev/random/randomdev.c +++ b/sys/dev/random/randomdev.c @@ -36,11 +36,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include @@ -50,7 +48,6 @@ #include #include -#include #include @@ -78,11 +75,12 @@ static struct cdevsw random_cdevsw = { /* dump */ nodump, /* psize */ nopsize, /* flags */ 0, + /* kqfilter */ NULL }; static void random_kthread(void *); static void random_harvest_internal(u_int64_t, void *, u_int, u_int, u_int, enum esource); -static void random_write_internal(void *, u_int); +static void random_write_internal(void *, int); /* Ring buffer holding harvested entropy */ static struct harvestring { @@ -106,6 +104,7 @@ static struct proc *random_kthread_proc; static dev_t random_dev; static dev_t urandom_dev; +/* ARGSUSED */ static int random_check_boolean(SYSCTL_HANDLER_ARGS) { @@ -138,8 +137,9 @@ SYSCTL_PROC(_kern_random_sys_harvest, OID_AUTO, interrupt, CTLTYPE_INT|CTLFLAG_RW, &harvest.interrupt, 0, random_check_boolean, "I", "Harvest IRQ entropy"); +/* ARGSUSED */ static int -random_open(dev_t dev, int flags, int fmt, struct thread *td) +random_open(dev_t dev __unused, int flags, int fmt __unused, struct thread *td) { int error; @@ -154,8 +154,9 @@ random_open(dev_t dev, int flags, int fmt, struct thread *td) return 0; } +/* ARGSUSED */ static int -random_close(dev_t dev, int flags, int fmt, struct thread *td) +random_close(dev_t dev __unused, int flags, int fmt __unused, struct thread *td) { if (flags & FWRITE) { if (!(suser(td->td_proc) || @@ -165,10 +166,11 @@ random_close(dev_t dev, int flags, int fmt, struct thread *td) return 0; } +/* ARGSUSED */ static int -random_read(dev_t dev, struct uio *uio, int flag) +random_read(dev_t dev __unused, struct uio *uio, int flag) { - u_int c, ret; + int c, ret; int error = 0; void *random_buf; @@ -181,8 +183,8 @@ random_read(dev_t dev, struct uio *uio, int flag) if (error != 0) return error; } - c = min(uio->uio_resid, PAGE_SIZE); - random_buf = (void *)malloc(c, M_TEMP, M_WAITOK); + c = uio->uio_resid < PAGE_SIZE ? uio->uio_resid : PAGE_SIZE; + random_buf = (void *)malloc((u_long)c, M_TEMP, M_WAITOK); while (uio->uio_resid > 0 && error == 0) { ret = read_random_real(random_buf, c); error = uiomove(random_buf, ret, uio); @@ -191,17 +193,20 @@ random_read(dev_t dev, struct uio *uio, int flag) return error; } +/* ARGSUSED */ static int -random_write(dev_t dev, struct uio *uio, int flag) +random_write(dev_t dev __unused, struct uio *uio, int flag __unused) { - u_int c; + int c; int error; void *random_buf; error = 0; random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); while (uio->uio_resid > 0) { - c = min(uio->uio_resid, PAGE_SIZE); + c = (int)(uio->uio_resid < PAGE_SIZE + ? uio->uio_resid + : PAGE_SIZE); error = uiomove(random_buf, c, uio); if (error) break; @@ -211,8 +216,10 @@ random_write(dev_t dev, struct uio *uio, int flag) return error; } +/* ARGSUSED */ static int -random_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) +random_ioctl(dev_t dev __unused, u_long cmd, caddr_t addr __unused, + int flags __unused, struct thread *td __unused) { switch (cmd) { /* Really handled in upper layer */ @@ -224,8 +231,9 @@ random_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) } } +/* ARGSUSED */ static int -random_poll(dev_t dev, int events, struct thread *td) +random_poll(dev_t dev __unused, int events, struct thread *td) { int revents; @@ -239,8 +247,9 @@ random_poll(dev_t dev, int events, struct thread *td) return revents; } +/* ARGSUSED */ static int -random_modevent(module_t mod, int type, void *data) +random_modevent(module_t mod __unused, int type, void *data __unused) { int error; @@ -306,11 +315,12 @@ random_modevent(module_t mod, int type, void *data) DEV_MODULE(random, random_modevent, NULL); +/* ARGSUSED */ static void -random_kthread(void *arg /* NOTUSED */) +random_kthread(void *arg __unused) { struct harvest *event; - int newtail, burst; + u_int newtail, burst; /* Drain the harvest queue (in 'burst' size chunks, * if 'burst' > 0. If 'burst' == 0, then completely @@ -365,8 +375,8 @@ static void random_harvest_internal(u_int64_t somecounter, void *entropy, u_int count, u_int bits, u_int frac, enum esource origin) { - struct harvest *harvest; - int newhead; + struct harvest *pharvest; + u_int newhead; newhead = (harvestring.head + 1) & HARVEST_RING_MASK; @@ -374,16 +384,17 @@ random_harvest_internal(u_int64_t somecounter, void *entropy, u_int count, /* Add the harvested data to the ring buffer */ - harvest = &harvestring.data[harvestring.head]; + pharvest = &harvestring.data[harvestring.head]; /* Stuff the harvested data into the ring */ - harvest->somecounter = somecounter; + pharvest->somecounter = somecounter; count = count > HARVESTSIZE ? HARVESTSIZE : count; - memcpy(harvest->entropy, entropy, count); - harvest->size = count; - harvest->bits = bits; - harvest->frac = frac; - harvest->source = origin < ENTROPYSOURCE ? origin : 0; + memcpy(pharvest->entropy, entropy, count); + pharvest->size = count; + pharvest->bits = bits; + pharvest->frac = frac; + pharvest->source = + origin < ENTROPYSOURCE ? origin : RANDOM_START; /* Bump the ring counter. This action is assumed * to be atomic. @@ -395,9 +406,9 @@ random_harvest_internal(u_int64_t somecounter, void *entropy, u_int count, } static void -random_write_internal(void *buf, u_int count) +random_write_internal(void *buf, int count) { - u_int i; + int i; /* Break the input up into HARVESTSIZE chunks. * The writer has too much control here, so "estimate" the @@ -418,7 +429,7 @@ random_write_internal(void *buf, u_int count) count %= HARVESTSIZE; if (count) { random_harvest_internal(get_cyclecount(), (char *)buf + i, - count, 0, 0, RANDOM_WRITE); + (u_int)count, 0, 0, RANDOM_WRITE); } } diff --git a/sys/dev/random/randomdev.h b/sys/dev/random/randomdev.h index 80a61ba18a7d..359dc269d50c 100644 --- a/sys/dev/random/randomdev.h +++ b/sys/dev/random/randomdev.h @@ -58,14 +58,14 @@ struct harvest { void random_init(void); void random_deinit(void); -void random_init_harvester(void (*)(u_int64_t, void *, u_int, u_int, u_int, enum esource), u_int (*)(void *, u_int)); +void random_init_harvester(void (*)(u_int64_t, void *, u_int, u_int, u_int, enum esource), int (*)(void *, int)); void random_deinit_harvester(void); void random_set_wakeup_exit(void *); void random_process_event(struct harvest *event); void random_reseed(void); void random_unblock(void); -u_int read_random_real(void *, u_int); +int read_random_real(void *, int); /* If this was c++, this would be a template */ #define RANDOM_CHECK_UINT(name, min, max) \ @@ -73,10 +73,10 @@ static int \ random_check_uint_##name(SYSCTL_HANDLER_ARGS) \ { \ if (oidp->oid_arg1 != NULL) { \ - if (*(u_int *)(oidp->oid_arg1) < min) \ - *(u_int *)(oidp->oid_arg1) = min; \ - else if (*(u_int *)(oidp->oid_arg1) > max) \ - *(u_int *)(oidp->oid_arg1) = max; \ + if (*(u_int *)(oidp->oid_arg1) <= (min)) \ + *(u_int *)(oidp->oid_arg1) = (min); \ + else if (*(u_int *)(oidp->oid_arg1) > (max)) \ + *(u_int *)(oidp->oid_arg1) = (max); \ } \ return sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, \ req); \ diff --git a/sys/dev/random/yarrow.c b/sys/dev/random/yarrow.c index 1554f06e3e92..8ab16b245e3b 100644 --- a/sys/dev/random/yarrow.c +++ b/sys/dev/random/yarrow.c @@ -29,13 +29,10 @@ #include #include #include -#include #include #include -#include #include #include -#include #include @@ -81,8 +78,9 @@ static struct mtx random_reseed_mtx; void random_process_event(struct harvest *event) { - u_int pl, src, overthreshhold[2]; + u_int pl, overthreshhold[2]; struct source *source; + enum esource src; /* Unpack the event into the appropriate source accumulator */ pl = random_state.which; @@ -98,7 +96,7 @@ random_process_event(struct harvest *event) /* Count the over-threshold sources in each pool */ for (pl = 0; pl < 2; pl++) { overthreshhold[pl] = 0; - for (src = 0; src < ENTROPYSOURCE; src++) { + for (src = RANDOM_START; src < ENTROPYSOURCE; src++) { if (random_state.pool[pl].source[src].bits > random_state.pool[pl].thresh) overthreshhold[pl]++; @@ -160,7 +158,8 @@ reseed(u_int fastslow) static struct yarrowhash context; u_char hash[KEYSIZE]; /* h' */ u_char temp[KEYSIZE]; - u_int i, j; + u_int i; + enum esource j; #ifdef DEBUG mtx_lock(&Giant); @@ -222,7 +221,7 @@ reseed(u_int fastslow) /* 5. Reset entropy estimate accumulators to zero */ for (i = 0; i <= fastslow; i++) { - for (j = 0; j < ENTROPYSOURCE; j++) { + for (j = RANDOM_START; j < ENTROPYSOURCE; j++) { random_state.pool[i].source[j].bits = 0; random_state.pool[i].source[j].frac = 0; } @@ -253,14 +252,14 @@ reseed(u_int fastslow) /* Internal function to do return processed entropy from the * Yarrow PRNG */ -u_int -read_random_real(void *buf, u_int count) +int +read_random_real(void *buf, int count) { static int cur = 0; static int gate = 1; static u_char genval[KEYSIZE]; - u_int i; - u_int retval; + int i; + int retval; /* The reseed task must not be jumped on */ mtx_lock(&random_reseed_mtx); @@ -270,9 +269,9 @@ read_random_real(void *buf, u_int count) random_state.outputblocks = 0; gate = 0; } - if (count >= sizeof(random_state.counter)) { + if (count > 0 && (size_t)count >= sizeof(random_state.counter)) { retval = 0; - for (i = 0; i < count; i += sizeof(random_state.counter)) { + for (i = 0; i < count; i += (int)sizeof(random_state.counter)) { random_state.counter[0]++; yarrow_encrypt(&random_state.key, random_state.counter, genval); @@ -283,7 +282,7 @@ read_random_real(void *buf, u_int count) generator_gate(); random_state.outputblocks = 0; } - retval += sizeof(random_state.counter); + retval += (int)sizeof(random_state.counter); } } else { @@ -291,8 +290,8 @@ read_random_real(void *buf, u_int count) random_state.counter[0]++; yarrow_encrypt(&random_state.key, random_state.counter, genval); - memcpy(buf, genval, count); - cur = sizeof(random_state.counter) - count; + memcpy(buf, genval, (size_t)count); + cur = (int)sizeof(random_state.counter) - count; if (++random_state.outputblocks >= random_state.gengateinterval) { generator_gate(); @@ -302,8 +301,9 @@ read_random_real(void *buf, u_int count) } else { retval = cur < count ? cur : count; - memcpy(buf, &genval[sizeof(random_state.counter) - cur], - retval); + memcpy(buf, + &genval[(int)sizeof(random_state.counter) - cur], + (size_t)retval); cur -= retval; } } diff --git a/sys/sys/random.h b/sys/sys/random.h index f2c89e65ead4..3cd147124f39 100644 --- a/sys/sys/random.h +++ b/sys/sys/random.h @@ -31,10 +31,17 @@ #ifdef _KERNEL -u_int read_random(void *, u_int); - -enum esource { RANDOM_WRITE, RANDOM_KEYBOARD, RANDOM_MOUSE, RANDOM_NET, - RANDOM_INTERRUPT, ENTROPYSOURCE }; +int read_random(void *, int); + +enum esource { + RANDOM_START = 0, + RANDOM_WRITE = 0, + RANDOM_KEYBOARD, + RANDOM_MOUSE, + RANDOM_NET, + RANDOM_INTERRUPT, + ENTROPYSOURCE +}; void random_harvest(void *, u_int, u_int, u_int, enum esource); /* Allow the sysadmin to select the broad category of -- cgit v1.3 From bbf09ad887f1ebc18052ee12f5074c05d69a4e46 Mon Sep 17 00:00:00 2001 From: Mark Murray Date: Mon, 15 Jul 2002 13:58:35 +0000 Subject: Upgrade the random device to use a "real" hash instead of building one out of a block cipher. This has 2 advantages: 1) The code is _much_ simpler 2) We aren't committing our security to one algorithm (much as we may think we trust AES). While I'm here, make an explicit reseed do a slow reseed instead of a fast; this is in line with what the original paper suggested. --- sys/conf/files | 1 + sys/dev/random/hash.c | 50 ++++++--------------------------------------- sys/dev/random/hash.h | 8 ++------ sys/dev/random/yarrow.c | 7 +++---- sys/modules/random/Makefile | 3 ++- 5 files changed, 14 insertions(+), 55 deletions(-) (limited to 'sys/dev/random/hash.h') diff --git a/sys/conf/files b/sys/conf/files index 5d25d3eab1a9..e27d63882c1a 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -507,6 +507,7 @@ dev/random/yarrow.c optional random dev/random/hash.c optional random crypto/rijndael/rijndael-alg-fst.c optional random crypto/rijndael/rijndael-api-fst.c optional random +crypto/sha2/sha2.c optional random dev/ray/if_ray.c optional ray card dev/ray/if_ray.c optional ray pccard dev/rp/rp.c optional rp diff --git a/sys/dev/random/hash.c b/sys/dev/random/hash.c index a9246c34db7c..98bd25356223 100644 --- a/sys/dev/random/hash.c +++ b/sys/dev/random/hash.c @@ -30,47 +30,22 @@ #include #include +#include #include -/* initialise the hash by zeroing it */ +/* initialise the hash */ void yarrow_hash_init(struct yarrowhash *context) { - rijndael_cipherInit(&context->cipher, MODE_CBC, NULL); - bzero(context->hash, KEYSIZE); - context->partial = 0; + SHA256_Init(&context->sha); } -/* Do a Davies-Meyer hash using a block cipher. - * H_0 = I - * H_i = E_M_i(H_i-1) ^ H_i-1 - */ +/* iterate the hash */ void yarrow_hash_iterate(struct yarrowhash *context, void *data, size_t size) { - u_char temp[KEYSIZE]; - u_int i, j; - union { - void *pv; - char *pc; - } trans; - - trans.pv = data; - for (i = 0; i < size; i++) { - context->accum[context->partial++] = trans.pc[i]; - if (context->partial == (KEYSIZE - 1)) { - rijndael_makeKey(&context->hashkey, DIR_ENCRYPT, - KEYSIZE*8, context->accum); - rijndael_blockEncrypt(&context->cipher, - &context->hashkey, context->hash, - KEYSIZE*8, temp); - for (j = 0; j < KEYSIZE; j++) - context->hash[j] ^= temp[j]; - bzero(context->accum, KEYSIZE); - context->partial = 0; - } - } + SHA256_Update(&context->sha, data, size); } /* Conclude by returning the hash in the supplied /buf/ which must be @@ -80,20 +55,7 @@ yarrow_hash_iterate(struct yarrowhash *context, void *data, size_t size) void yarrow_hash_finish(struct yarrowhash *context, void *buf) { - u_char temp[KEYSIZE]; - int i; - - if (context->partial) { - rijndael_makeKey(&context->hashkey, DIR_ENCRYPT, - KEYSIZE*8, context->accum); - rijndael_blockEncrypt(&context->cipher, - &context->hashkey, context->hash, - KEYSIZE*8, temp); - for (i = 0; i < KEYSIZE; i++) - context->hash[i] ^= temp[i]; - } - memcpy(buf, context->hash, KEYSIZE); - bzero(context->hash, KEYSIZE); + SHA256_Final(buf, &context->sha); } /* Initialise the encryption routine by setting up the key schedule diff --git a/sys/dev/random/hash.h b/sys/dev/random/hash.h index 5a308210d690..b307bfcb09f2 100644 --- a/sys/dev/random/hash.h +++ b/sys/dev/random/hash.h @@ -26,14 +26,10 @@ * $FreeBSD$ */ -#define KEYSIZE 32 /* in bytes - 32 bytes == 256 bits */ +#define KEYSIZE 32 /* (in bytes) 32 bytes == 256 bits */ struct yarrowhash { /* Big! Make static! */ - keyInstance hashkey; /* Data cycles through here */ - cipherInstance cipher; /* Rijndael internal */ - u_char hash[KEYSIZE]; /* Repeatedly encrypted */ - char accum[KEYSIZE]; /* Accumulate partial chunks */ - u_int partial; /* Keep track of < KEYSIZE chunks */ + SHA256_CTX sha; }; struct yarrowkey { /* Big! Make static! */ diff --git a/sys/dev/random/yarrow.c b/sys/dev/random/yarrow.c index dd79c340a415..94078927e95e 100644 --- a/sys/dev/random/yarrow.c +++ b/sys/dev/random/yarrow.c @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -249,9 +250,7 @@ reseed(u_int fastslow) random_unblock(); } -/* Internal function to do return processed entropy from the - * Yarrow PRNG - */ +/* Internal function to return processed entropy from the PRNG */ int read_random_real(void *buf, int count) { @@ -343,5 +342,5 @@ generator_gate(void) void random_reseed(void) { - reseed(FAST); + reseed(SLOW); } diff --git a/sys/modules/random/Makefile b/sys/modules/random/Makefile index d88a19b22a80..1e7286892624 100644 --- a/sys/modules/random/Makefile +++ b/sys/modules/random/Makefile @@ -2,10 +2,11 @@ .PATH: ${.CURDIR}/../../dev/random .PATH: ${.CURDIR}/../../crypto/rijndael +.PATH: ${.CURDIR}/../../crypto/sha2 KMOD= random SRCS= randomdev.c yarrow.c hash.c -SRCS+= rijndael-alg-fst.c rijndael-api-fst.c +SRCS+= rijndael-alg-fst.c rijndael-api-fst.c sha2.c SRCS+= bus_if.h device_if.h vnode_if.h CFLAGS+= -I${.CURDIR}/../.. -- cgit v1.3 From e7806b4c0eb398aba8b6e8ddeda96e6ddd9305ae Mon Sep 17 00:00:00 2001 From: Mark Murray Date: Fri, 9 Apr 2004 15:47:10 +0000 Subject: Reorganise the entropy device so that high-yield entropy sources can more easily be used INSTEAD OF the hard-working Yarrow. The only hardware source used at this point is the one inside the VIA C3 Nehemiah (Stepping 3 and above) CPU. More sources will be added in due course. Contributions welcome! --- sys/conf/files | 3 + sys/dev/random/harvest.c | 26 ++- sys/dev/random/hash.c | 2 +- sys/dev/random/hash.h | 2 +- sys/dev/random/nehemiah.c | 66 +++++++ sys/dev/random/nehemiah.h | 29 +++ sys/dev/random/probe.c | 68 +++++++ sys/dev/random/randomdev.c | 406 ++++++++-------------------------------- sys/dev/random/randomdev.h | 72 ++----- sys/dev/random/randomdev_soft.c | 369 ++++++++++++++++++++++++++++++++++++ sys/dev/random/randomdev_soft.h | 93 +++++++++ sys/dev/random/yarrow.c | 76 +++++--- sys/dev/random/yarrow.h | 2 +- sys/modules/random/Makefile | 4 +- 14 files changed, 795 insertions(+), 423 deletions(-) create mode 100644 sys/dev/random/nehemiah.c create mode 100644 sys/dev/random/nehemiah.h create mode 100644 sys/dev/random/probe.c create mode 100644 sys/dev/random/randomdev_soft.c create mode 100644 sys/dev/random/randomdev_soft.h (limited to 'sys/dev/random/hash.h') diff --git a/sys/conf/files b/sys/conf/files index 4bc5ead245e1..73f3754eb5ff 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -608,6 +608,9 @@ dev/puc/puc_sbus.c optional puc sbus dev/puc/pucdata.c optional puc pci dev/random/harvest.c standard dev/random/randomdev.c optional random +dev/random/randomdev_soft.c optional random +dev/random/nehemiah.c optional random +dev/random/probe.c optional random dev/random/yarrow.c optional random dev/random/hash.c optional random crypto/rijndael/rijndael-alg-fst.c optional random diff --git a/sys/dev/random/harvest.c b/sys/dev/random/harvest.c index eb84268c7773..c634c3814d53 100644 --- a/sys/dev/random/harvest.c +++ b/sys/dev/random/harvest.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000, 2001, 2002, 2003 Mark R V Murray + * Copyright (c) 2000-2004 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,29 +37,29 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include +#include #include -#include +#include static int read_random_phony(void *, int); /* Structure holding the desired entropy sources */ -struct harvest_select harvest = { 0, 0, 0 }; +struct harvest_select harvest = { 0, 0, 0, 0 }; /* hold the address of the routine which is actually called if * the randomdev is loaded */ -static void (*reap_func)(u_int64_t, void *, u_int, u_int, u_int, enum esource) - = NULL; +static void (*reap_func)(u_int64_t, const void *, u_int, u_int, u_int, + enum esource) = NULL; static int (*read_func)(void *, int) = read_random_phony; /* Initialise the harvester at load time */ void -random_init_harvester(void (*reaper)(u_int64_t, void *, u_int, u_int, u_int, - enum esource), int (*reader)(void *, int)) +random_yarrow_init_harvester(void (*reaper)(u_int64_t, const void *, u_int, + u_int, u_int, enum esource), int (*reader)(void *, int)) { reap_func = reaper; read_func = reader; @@ -67,7 +67,7 @@ random_init_harvester(void (*reaper)(u_int64_t, void *, u_int, u_int, u_int, /* Deinitialise the harvester at unload time */ void -random_deinit_harvester(void) +random_yarrow_deinit_harvester(void) { reap_func = NULL; read_func = read_random_phony; @@ -91,7 +91,7 @@ random_harvest(void *entropy, u_int count, u_int bits, u_int frac, int read_random(void *buf, int count) { - return (*read_func)(buf, count); + return ((*read_func)(buf, count)); } /* If the entropy device is not loaded, make a token effort to @@ -109,13 +109,11 @@ read_random_phony(void *buf, int count) /* Fill buf[] with random(9) output */ for (i = 0; i < count; i+= (int)sizeof(u_long)) { randval = random(); - size = (count - i) < (int)sizeof(u_long) - ? (count - i) - : sizeof(u_long); + size = MIN(count - i, sizeof(u_long)); memcpy(&((char *)buf)[i], &randval, (size_t)size); } - return count; + return (count); } /* Helper routine to enable kthread_exit() to work while the module is diff --git a/sys/dev/random/hash.c b/sys/dev/random/hash.c index 53ddb3cf0c59..95fc8e943689 100644 --- a/sys/dev/random/hash.c +++ b/sys/dev/random/hash.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000, 2001, 2002, 2003 Mark R V Murray + * Copyright (c) 2000-2004 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/sys/dev/random/hash.h b/sys/dev/random/hash.h index b307bfcb09f2..8580d145d683 100644 --- a/sys/dev/random/hash.h +++ b/sys/dev/random/hash.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000 Mark R V Murray + * Copyright (c) 2000-2004 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/sys/dev/random/nehemiah.c b/sys/dev/random/nehemiah.c new file mode 100644 index 000000000000..e496828a01ca --- /dev/null +++ b/sys/dev/random/nehemiah.c @@ -0,0 +1,66 @@ +/*- + * Copyright (c) 2004 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$"); + +#include +#include +#include +#include +#include + +#include + +static int random_nehemiah_read(void *, int); + +struct random_systat random_nehemiah = { + .ident = "Hardware, VIA Nehemiah", + .init = (random_init_func_t *)random_null_func, + .deinit = (random_deinit_func_t *)random_null_func, + .read = random_nehemiah_read, + .write = (random_write_func_t *)random_null_func, + .reseed = (random_reseed_func_t *)random_null_func, + .seeded = 1, +}; + +/* ARGSUSED */ +static int +random_nehemiah_read(void *buf, int c) +{ +#if (defined(__GNUC__) || defined(__INTEL_COMPILER)) && defined(__i386__) + int count = c; + int rate = 0; + + /* VIA C3 Nehemiah "rep; xstore" */ + __asm __volatile("rep; .byte 0x0f, 0xa7, 0xc0" + : "+D" (buf), "+c" (count), "=d" (rate) + : + : "memory"); +#endif + return (c); +} diff --git a/sys/dev/random/nehemiah.h b/sys/dev/random/nehemiah.h new file mode 100644 index 000000000000..b35fb3fb2262 --- /dev/null +++ b/sys/dev/random/nehemiah.h @@ -0,0 +1,29 @@ +/*- + * Copyright (c) 2000-2004 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$ + */ + +extern struct random_systat random_nehemiah; diff --git a/sys/dev/random/probe.c b/sys/dev/random/probe.c new file mode 100644 index 000000000000..ef3ab01e8a8d --- /dev/null +++ b/sys/dev/random/probe.c @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 2004 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$"); + +#include +#include +#include +#include +#include +#include + +#if defined(__i386__) +#include +#endif + +#include +#include +#include + +void +random_ident_hardware(struct random_systat *systat) +{ +#if defined(__i386__) + u_int regs[4]; +#endif + + /* Set default to software */ + *systat = random_yarrow; + + /* Then go looking for hardware */ +#if defined(__i386__) + do_cpuid(1, regs); + if ((regs[0] & 0xf) >= 3) { + do_cpuid(0xc0000000, regs); + if (regs[0] == 0xc0000001) { + do_cpuid(0xc0000001, regs); + if ((regs[3] & 0x0c) == 0x0c) + *systat = random_nehemiah; + } + } +#endif +} diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c index bc5f1666b1ad..63af98ac387a 100644 --- a/sys/dev/random/randomdev.c +++ b/sys/dev/random/randomdev.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000, 2001, 2002, 2003 Mark R V Murray + * Copyright (c) 2000-2004 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,9 +41,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include -#include #include #include #include @@ -53,150 +51,96 @@ __FBSDID("$FreeBSD$"); #include -static d_close_t random_close; -static d_read_t random_read; -static d_write_t random_write; -static d_ioctl_t random_ioctl; -static d_poll_t random_poll; - #define RANDOM_MINOR 0 -#define RANDOM_FIFO_MAX 256 /* How many events to queue up */ +static d_close_t random_close; +static d_read_t random_read; +static d_write_t random_write; +static d_ioctl_t random_ioctl; +static d_poll_t random_poll; static struct cdevsw random_cdevsw = { - .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, - .d_close = random_close, - .d_read = random_read, - .d_write = random_write, - .d_ioctl = random_ioctl, - .d_poll = random_poll, - .d_name = "random", -}; - -static void random_kthread(void *); -static void random_harvest_internal(u_int64_t, void *, u_int, u_int, u_int, enum esource); -static void random_write_internal(void *, int); - -MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers"); - -/* Lockable FIFO queue holding entropy buffers */ -struct entropyfifo { - struct mtx lock; - int count; - STAILQ_HEAD(harvestlist, harvest) head; + .d_version = D_VERSION, + .d_close = random_close, + .d_read = random_read, + .d_write = random_write, + .d_ioctl = random_ioctl, + .d_poll = random_poll, + .d_name = "random", }; -/* Empty entropy buffers */ -static struct entropyfifo emptyfifo; -#define EMPTYBUFFERS 1024 +static void *random_buf; -/* Harvested entropy */ -static struct entropyfifo harvestfifo[ENTROPYSOURCE]; - -static struct random_systat { - u_int seeded; /* 0 causes blocking 1 allows normal output */ - struct selinfo rsel; /* For poll(2) */ -} random_systat; - -/* <0 to end the kthread, 0 to let it run */ -static int random_kthread_control = 0; - -static struct proc *random_kthread_proc; +struct random_systat random_systat; /* For use with make_dev(9)/destroy_dev(9). */ -static dev_t random_dev; +static dev_t random_dev; -/* ARGSUSED */ -static int -random_check_boolean(SYSCTL_HANDLER_ARGS) +/* Used to fake out unused random calls in random_systat */ +void +random_null_func(void) { - if (oidp->oid_arg1 != NULL && *(u_int *)(oidp->oid_arg1) != 0) - *(u_int *)(oidp->oid_arg1) = 1; - return sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); } -SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, - 0, "Random Number Generator"); -SYSCTL_NODE(_kern_random, OID_AUTO, sys, CTLFLAG_RW, - 0, "Entropy Device Parameters"); -SYSCTL_PROC(_kern_random_sys, OID_AUTO, seeded, - CTLTYPE_INT|CTLFLAG_RW, &random_systat.seeded, 1, - random_check_boolean, "I", "Seeded State"); -SYSCTL_NODE(_kern_random_sys, OID_AUTO, harvest, CTLFLAG_RW, - 0, "Entropy Sources"); -SYSCTL_PROC(_kern_random_sys_harvest, OID_AUTO, ethernet, - CTLTYPE_INT|CTLFLAG_RW, &harvest.ethernet, 0, - random_check_boolean, "I", "Harvest NIC entropy"); -SYSCTL_PROC(_kern_random_sys_harvest, OID_AUTO, point_to_point, - CTLTYPE_INT|CTLFLAG_RW, &harvest.point_to_point, 0, - random_check_boolean, "I", "Harvest serial net entropy"); -SYSCTL_PROC(_kern_random_sys_harvest, OID_AUTO, interrupt, - CTLTYPE_INT|CTLFLAG_RW, &harvest.interrupt, 0, - random_check_boolean, "I", "Harvest IRQ entropy"); -SYSCTL_PROC(_kern_random_sys_harvest, OID_AUTO, swi, - CTLTYPE_INT|CTLFLAG_RW, &harvest.swi, 0, - random_check_boolean, "I", "Harvest SWI entropy"); - /* ARGSUSED */ static int -random_close(dev_t dev __unused, int flags, int fmt __unused, struct thread *td) +random_close(dev_t dev __unused, int flags, int fmt __unused, + struct thread *td) { - if (flags & FWRITE) { - if (suser(td) == 0 && securelevel_gt(td->td_ucred, 0) == 0) - random_reseed(); + if ((flags & FWRITE) && (suser(td) == 0) + && (securelevel_gt(td->td_ucred, 0) == 0)) { + mtx_lock(&random_systat.lock); + (*random_systat.reseed)(); + random_systat.seeded = 1; + mtx_unlock(&random_systat.lock); } - return 0; + return (0); } /* ARGSUSED */ static int random_read(dev_t dev __unused, struct uio *uio, int flag) { - int c, ret; - int error = 0; - void *random_buf; + int c, error = 0; - while (!random_systat.seeded) { + /* Blocking logic */ + while (!random_systat.seeded && !error) { if (flag & IO_NDELAY) - error = EWOULDBLOCK; + error = EWOULDBLOCK; else - error = tsleep(&random_systat, PUSER|PCATCH, - "block", 0); - if (error != 0) - return error; + error = tsleep(&random_systat, + PUSER | PCATCH, "block", 0); } - c = uio->uio_resid < PAGE_SIZE ? uio->uio_resid : PAGE_SIZE; - random_buf = (void *)malloc((u_long)c, M_TEMP, M_WAITOK); - while (uio->uio_resid > 0 && error == 0) { - ret = read_random_real(random_buf, c); - error = uiomove(random_buf, ret, uio); + + /* The actual read */ + if (!error) { + mtx_lock(&random_systat.lock); + while (uio->uio_resid > 0 && !error) { + c = MIN(uio->uio_resid, PAGE_SIZE); + c = (*random_systat.read)(random_buf, c); + error = uiomove(random_buf, c, uio); + } + mtx_unlock(&random_systat.lock); } - free(random_buf, M_TEMP); - return error; + return (error); } /* ARGSUSED */ static int random_write(dev_t dev __unused, struct uio *uio, int flag __unused) { - int c; - int error; - void *random_buf; + int c, error = 0; - error = 0; - random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); + mtx_lock(&random_systat.lock); while (uio->uio_resid > 0) { - c = (int)(uio->uio_resid < PAGE_SIZE - ? uio->uio_resid - : PAGE_SIZE); + c = MIN((int)uio->uio_resid, PAGE_SIZE); error = uiomove(random_buf, c, uio); if (error) break; - random_write_internal(random_buf, c); + (*random_systat.write)(random_buf, c); } - free(random_buf, M_TEMP); - return error; + mtx_unlock(&random_systat.lock); + return (error); } /* ARGSUSED */ @@ -204,264 +148,70 @@ static int random_ioctl(dev_t dev __unused, u_long cmd, caddr_t addr __unused, int flags __unused, struct thread *td __unused) { + int error = 0; + switch (cmd) { - /* Really handled in upper layer */ + /* Really handled in upper layer */ case FIOASYNC: case FIONBIO: - return 0; + break; default: - return ENOTTY; + error = ENOTTY; } + return (error); } /* ARGSUSED */ static int random_poll(dev_t dev __unused, int events, struct thread *td) { - int revents; + int revents = 0; - revents = 0; if (events & (POLLIN | POLLRDNORM)) { if (random_systat.seeded) revents = events & (POLLIN | POLLRDNORM); else selrecord(td, &random_systat.rsel); } - return revents; + return (revents); } /* ARGSUSED */ static int random_modevent(module_t mod __unused, int type, void *data __unused) { - int error, i; - struct harvest *np; + int error = 0; - switch(type) { + switch (type) { case MOD_LOAD: - random_init(); - - /* This can be turned off by the very paranoid - * a reseed will turn it back on. - */ - random_systat.seeded = 1; - - /* Initialise the harvest fifos */ - STAILQ_INIT(&emptyfifo.head); - emptyfifo.count = 0; - mtx_init(&emptyfifo.lock, "entropy harvest buffers", NULL, - MTX_SPIN); - for (i = 0; i < EMPTYBUFFERS; i++) { - np = malloc(sizeof(struct harvest), M_ENTROPY, - M_WAITOK); - STAILQ_INSERT_TAIL(&emptyfifo.head, np, next); - } - for (i = 0; i < ENTROPYSOURCE; i++) { - STAILQ_INIT(&harvestfifo[i].head); - harvestfifo[i].count = 0; - mtx_init(&harvestfifo[i].lock, "entropy harvest", NULL, - MTX_SPIN); - } - - if (bootverbose) - printf("random: \n"); - random_dev = make_dev(&random_cdevsw, RANDOM_MINOR, UID_ROOT, - GID_WHEEL, 0666, "random"); - make_dev_alias(random_dev, "urandom"); + random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); + random_ident_hardware(&random_systat); + mtx_init(&random_systat.lock, "entropy device lock", + NULL, MTX_DEF); + (*random_systat.init)(); - /* Start the hash/reseed thread */ - error = kthread_create(random_kthread, NULL, - &random_kthread_proc, RFHIGHPID, 0, "random"); - if (error != 0) - return error; + printf("random: \n", random_systat.ident); - /* Register the randomness harvesting routine */ - random_init_harvester(random_harvest_internal, - read_random_real); + random_dev = make_dev(&random_cdevsw, RANDOM_MINOR, + UID_ROOT, GID_WHEEL, 0666, "random"); + make_dev_alias(random_dev, "urandom"); /* XXX Deprecated */ - return 0; + break; case MOD_UNLOAD: - /* Deregister the randomness harvesting routine */ - random_deinit_harvester(); - - /* Command the hash/reseed thread to end and - * wait for it to finish - */ - random_kthread_control = -1; - tsleep((void *)&random_kthread_control, PUSER, "term", 0); - - /* Destroy the harvest fifos */ - while (!STAILQ_EMPTY(&emptyfifo.head)) { - np = STAILQ_FIRST(&emptyfifo.head); - STAILQ_REMOVE_HEAD(&emptyfifo.head, next); - free(np, M_ENTROPY); - } - mtx_destroy(&emptyfifo.lock); - for (i = 0; i < ENTROPYSOURCE; i++) { - while (!STAILQ_EMPTY(&harvestfifo[i].head)) { - np = STAILQ_FIRST(&harvestfifo[i].head); - STAILQ_REMOVE_HEAD(&harvestfifo[i].head, next); - free(np, M_ENTROPY); - } - mtx_destroy(&harvestfifo[i].lock); - } - - random_deinit(); + (*random_systat.deinit)(); + free(random_buf, M_TEMP); + mtx_destroy(&random_systat.lock); destroy_dev(random_dev); - return 0; + + break; case MOD_SHUTDOWN: - return 0; + break; - default: - return EOPNOTSUPP; } + return (error); } DEV_MODULE(random, random_modevent, NULL); - -/* ARGSUSED */ -static void -random_kthread(void *arg __unused) -{ - struct harvest *event = NULL; - int found, active; - enum esource source; - - /* Process until told to stop */ - for (; random_kthread_control == 0;) { - - active = 0; - - /* Cycle through all the entropy sources */ - for (source = 0; source < ENTROPYSOURCE; source++) { - - found = 0; - - /* Lock up queue draining */ - mtx_lock_spin(&harvestfifo[source].lock); - - if (!STAILQ_EMPTY(&harvestfifo[source].head)) { - - /* Get a harvested entropy event */ - harvestfifo[source].count--; - event = STAILQ_FIRST(&harvestfifo[source].head); - STAILQ_REMOVE_HEAD(&harvestfifo[source].head, - next); - - active = found = 1; - - } - - /* Unlock the queue */ - mtx_unlock_spin(&harvestfifo[source].lock); - - /* Deal with the event and dispose of it */ - if (found) { - - random_process_event(event); - - /* Lock the empty event buffer fifo */ - mtx_lock_spin(&emptyfifo.lock); - - STAILQ_INSERT_TAIL(&emptyfifo.head, event, next); - - mtx_unlock_spin(&emptyfifo.lock); - - } - - } - - /* Found nothing, so don't belabour the issue */ - if (!active) - tsleep(&harvestfifo, PUSER, "-", hz/10); - - } - - random_set_wakeup_exit(&random_kthread_control); - /* NOTREACHED */ -} - -/* Entropy harvesting routine. This is supposed to be fast; do - * not do anything slow in here! - */ -static void -random_harvest_internal(u_int64_t somecounter, void *entropy, u_int count, - u_int bits, u_int frac, enum esource origin) -{ - struct harvest *event; - - /* Lock the particular fifo */ - mtx_lock_spin(&harvestfifo[origin].lock); - - /* Don't make the harvest queues too big - help to prevent - * low-grade entropy swamping - */ - if (harvestfifo[origin].count < RANDOM_FIFO_MAX) { - - /* Lock the empty event buffer fifo */ - mtx_lock_spin(&emptyfifo.lock); - - if (!STAILQ_EMPTY(&emptyfifo.head)) { - event = STAILQ_FIRST(&emptyfifo.head); - STAILQ_REMOVE_HEAD(&emptyfifo.head, next); - } - else - event = NULL; - - mtx_unlock_spin(&emptyfifo.lock); - - /* If we didn't obtain a buffer, tough */ - if (event) { - - /* Add the harvested data to the fifo */ - harvestfifo[origin].count++; - event->somecounter = somecounter; - event->size = count; - event->bits = bits; - event->frac = frac; - event->source = origin; - - /* XXXX Come back and make this dynamic! */ - count = count > HARVESTSIZE ? HARVESTSIZE : count; - memcpy(event->entropy, entropy, count); - - STAILQ_INSERT_TAIL(&harvestfifo[origin].head, event, next); - } - - } - - mtx_unlock_spin(&harvestfifo[origin].lock); - -} - -static void -random_write_internal(void *buf, int count) -{ - int i; - u_int chunk; - - /* Break the input up into HARVESTSIZE chunks. - * The writer has too much control here, so "estimate" the - * the entropy as zero. - */ - for (i = 0; i < count; i += HARVESTSIZE) { - chunk = HARVESTSIZE; - if (i + chunk >= count) - chunk = (u_int)(count - i); - random_harvest_internal(get_cyclecount(), (char *)buf + i, - chunk, 0, 0, RANDOM_WRITE); - } -} - -void -random_unblock(void) -{ - if (!random_systat.seeded) { - random_systat.seeded = 1; - selwakeuppri(&random_systat.rsel, PUSER); - wakeup(&random_systat); - } -} diff --git a/sys/dev/random/randomdev.h b/sys/dev/random/randomdev.h index aa23fc8e7b1b..d5e064fb4643 100644 --- a/sys/dev/random/randomdev.h +++ b/sys/dev/random/randomdev.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2001 Mark R V Murray + * Copyright (c) 2000-2004 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,57 +30,25 @@ * and non algorithm-specific for the entropy processor */ -/* #define ENTROPYSOURCE nn entropy sources (actually classes) - * This is properly defined in - * an enum in sys/random.h - */ - -/* Cryptographic block size in bits */ -#define BLOCKSIZE 256 - -/* The ring size _MUST_ be a power of 2 */ -#define HARVEST_RING_SIZE 1024 /* harvest ring buffer size */ -#define HARVEST_RING_MASK (HARVEST_RING_SIZE - 1) - -#define HARVESTSIZE 16 /* max size of each harvested entropy unit */ - -SYSCTL_DECL(_kern_random); - -MALLOC_DECLARE(M_ENTROPY); - -/* These are used to queue harvested packets of entropy. The entropy - * buffer size is pretty arbitrary. - */ -struct harvest { - uintmax_t somecounter; /* fast counter for clock jitter */ - u_char entropy[HARVESTSIZE]; /* the harvested entropy */ - u_int size, bits, frac; /* stats about the entropy */ - enum esource source; /* stats about the entropy */ - STAILQ_ENTRY(harvest) next; /* next item on the list */ +typedef void random_init_func_t(void); +typedef void random_deinit_func_t(void); +typedef int random_read_func_t(void *, int); +typedef void random_write_func_t(void *, int); +typedef void random_reseed_func_t(void); + +struct random_systat { + struct selinfo rsel; + const char *ident; + int seeded; + random_init_func_t *init; + random_deinit_func_t *deinit; + random_read_func_t *read; + random_write_func_t *write; + random_reseed_func_t *reseed; + struct mtx lock; }; -void random_init(void); -void random_deinit(void); -void random_init_harvester(void (*)(u_int64_t, void *, u_int, u_int, u_int, enum esource), int (*)(void *, int)); -void random_deinit_harvester(void); -void random_set_wakeup_exit(void *); -void random_process_event(struct harvest *event); -void random_reseed(void); -void random_unblock(void); - -int read_random_real(void *, int); +extern struct random_systat random_systat; -/* If this was c++, this would be a template */ -#define RANDOM_CHECK_UINT(name, min, max) \ -static int \ -random_check_uint_##name(SYSCTL_HANDLER_ARGS) \ -{ \ - if (oidp->oid_arg1 != NULL) { \ - if (*(u_int *)(oidp->oid_arg1) <= (min)) \ - *(u_int *)(oidp->oid_arg1) = (min); \ - else if (*(u_int *)(oidp->oid_arg1) > (max)) \ - *(u_int *)(oidp->oid_arg1) = (max); \ - } \ - return sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, \ - req); \ -} +extern void random_ident_hardware(struct random_systat *); +extern void random_null_func(void); diff --git a/sys/dev/random/randomdev_soft.c b/sys/dev/random/randomdev_soft.c new file mode 100644 index 000000000000..e342436ea58b --- /dev/null +++ b/sys/dev/random/randomdev_soft.c @@ -0,0 +1,369 @@ +/*- + * Copyright (c) 2000-2004 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$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#define RANDOM_FIFO_MAX 256 /* How many events to queue up */ + +static void random_kthread(void *); +static void +random_harvest_internal(u_int64_t, const void *, u_int, + u_int, u_int, enum esource); + +struct random_systat random_yarrow = { + .ident = "Software, Yarrow", + .init = random_yarrow_init, + .deinit = random_yarrow_deinit, + .read = random_yarrow_read, + .write = random_yarrow_write, + .reseed = random_yarrow_reseed, + .seeded = 0, +}; + +MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers"); + +/* Lockable FIFO queue holding entropy buffers */ +struct entropyfifo { + struct mtx lock; + int count; + STAILQ_HEAD(harvestlist, harvest) head; +}; + +/* Empty entropy buffers */ +static struct entropyfifo emptyfifo; + +#define EMPTYBUFFERS 1024 + +/* Harvested entropy */ +static struct entropyfifo harvestfifo[ENTROPYSOURCE]; + +/* <0 to end the kthread, 0 to let it run */ +static int random_kthread_control = 0; + +static struct proc *random_kthread_proc; + +/* List for the dynamic sysctls */ +struct sysctl_ctx_list random_clist; + +/* ARGSUSED */ +static int +random_check_boolean(SYSCTL_HANDLER_ARGS) +{ + if (oidp->oid_arg1 != NULL && *(u_int *)(oidp->oid_arg1) != 0) + *(u_int *)(oidp->oid_arg1) = 1; + return sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); +} + +/* ARGSUSED */ +void +random_yarrow_init(void) +{ + int error, i; + struct harvest *np; + struct sysctl_oid *o, *random_o, *random_sys_o, *random_sys_harvest_o; + enum esource e; + + o = SYSCTL_ADD_NODE(&random_clist, + SYSCTL_STATIC_CHILDREN(_kern), + OID_AUTO, "random", CTLFLAG_RW, 0, + "Software Random Number Generator"); + + random_o = o; + + random_yarrow_init_alg(&random_clist, random_o); + + o = SYSCTL_ADD_NODE(&random_clist, + SYSCTL_CHILDREN(random_o), + OID_AUTO, "sys", CTLFLAG_RW, 0, + "Entropy Device Parameters"); + + random_sys_o = o; + + o = SYSCTL_ADD_PROC(&random_clist, + SYSCTL_CHILDREN(random_sys_o), + OID_AUTO, "seeded", CTLTYPE_INT | CTLFLAG_RW, + &random_systat.seeded, 0, random_check_boolean, "I", + "Seeded State"); + + o = SYSCTL_ADD_NODE(&random_clist, + SYSCTL_CHILDREN(random_sys_o), + OID_AUTO, "harvest", CTLFLAG_RW, 0, + "Entropy Sources"); + + random_sys_harvest_o = o; + + o = SYSCTL_ADD_PROC(&random_clist, + SYSCTL_CHILDREN(random_sys_harvest_o), + OID_AUTO, "ethernet", CTLTYPE_INT | CTLFLAG_RW, + &harvest.ethernet, 0, random_check_boolean, "I", + "Harvest NIC entropy"); + o = SYSCTL_ADD_PROC(&random_clist, + SYSCTL_CHILDREN(random_sys_harvest_o), + OID_AUTO, "point_to_point", CTLTYPE_INT | CTLFLAG_RW, + &harvest.point_to_point, 0, random_check_boolean, "I", + "Harvest serial net entropy"); + o = SYSCTL_ADD_PROC(&random_clist, + SYSCTL_CHILDREN(random_sys_harvest_o), + OID_AUTO, "interrupt", CTLTYPE_INT | CTLFLAG_RW, + &harvest.interrupt, 0, random_check_boolean, "I", + "Harvest IRQ entropy"); + o = SYSCTL_ADD_PROC(&random_clist, + SYSCTL_CHILDREN(random_sys_harvest_o), + OID_AUTO, "swi", CTLTYPE_INT | CTLFLAG_RW, + &harvest.swi, 0, random_check_boolean, "I", + "Harvest SWI entropy"); + + /* Initialise the harvest fifos */ + STAILQ_INIT(&emptyfifo.head); + emptyfifo.count = 0; + mtx_init(&emptyfifo.lock, "entropy harvest buffers", NULL, MTX_SPIN); + for (i = 0; i < EMPTYBUFFERS; i++) { + np = malloc(sizeof(struct harvest), M_ENTROPY, M_WAITOK); + STAILQ_INSERT_TAIL(&emptyfifo.head, np, next); + } + for (e = RANDOM_START; e < ENTROPYSOURCE; e++) { + STAILQ_INIT(&harvestfifo[e].head); + harvestfifo[e].count = 0; + mtx_init(&harvestfifo[e].lock, "entropy harvest", NULL, + MTX_SPIN); + } + + /* Start the hash/reseed thread */ + error = kthread_create(random_kthread, NULL, + &random_kthread_proc, RFHIGHPID, 0, "yarrow"); + if (error != 0) + panic("Cannot create entropy maintenance thread."); + + /* Register the randomness harvesting routine */ + random_yarrow_init_harvester(random_harvest_internal, + random_yarrow_read); +} + +/* ARGSUSED */ +void +random_yarrow_deinit(void) +{ + struct harvest *np; + enum esource e; + + /* Deregister the randomness harvesting routine */ + random_yarrow_deinit_harvester(); + + /* + * Command the hash/reseed thread to end and wait for it to finish + */ + random_kthread_control = -1; + tsleep((void *)&random_kthread_control, PUSER, "term", 0); + + /* Destroy the harvest fifos */ + while (!STAILQ_EMPTY(&emptyfifo.head)) { + np = STAILQ_FIRST(&emptyfifo.head); + STAILQ_REMOVE_HEAD(&emptyfifo.head, next); + free(np, M_ENTROPY); + } + mtx_destroy(&emptyfifo.lock); + for (e = RANDOM_START; e < ENTROPYSOURCE; e++) { + while (!STAILQ_EMPTY(&harvestfifo[e].head)) { + np = STAILQ_FIRST(&harvestfifo[e].head); + STAILQ_REMOVE_HEAD(&harvestfifo[e].head, next); + free(np, M_ENTROPY); + } + mtx_destroy(&harvestfifo[e].lock); + } + + random_yarrow_deinit_alg(); + + sysctl_ctx_free(&random_clist); +} + +/* ARGSUSED */ +static void +random_kthread(void *arg __unused) +{ + struct harvest *event = NULL; + int found, active; + enum esource source; + + /* Process until told to stop */ + for (; random_kthread_control == 0;) { + + active = 0; + + /* Cycle through all the entropy sources */ + for (source = RANDOM_START; source < ENTROPYSOURCE; source++) { + + found = 0; + + /* Lock up queue draining */ + mtx_lock_spin(&harvestfifo[source].lock); + + if (!STAILQ_EMPTY(&harvestfifo[source].head)) { + + /* Get a harvested entropy event */ + harvestfifo[source].count--; + event = STAILQ_FIRST(&harvestfifo[source].head); + STAILQ_REMOVE_HEAD(&harvestfifo[source].head, + next); + + active = found = 1; + + } + /* Unlock the queue */ + mtx_unlock_spin(&harvestfifo[source].lock); + + /* Deal with the event and dispose of it */ + if (found) { + + random_process_event(event); + + /* Lock the empty event buffer fifo */ + mtx_lock_spin(&emptyfifo.lock); + + STAILQ_INSERT_TAIL(&emptyfifo.head, event, + next); + + mtx_unlock_spin(&emptyfifo.lock); + + } + } + + /* Found nothing, so don't belabour the issue */ + if (!active) + tsleep(&harvestfifo, PUSER, "-", hz / 10); + + } + + random_set_wakeup_exit(&random_kthread_control); + /* NOTREACHED */ +} + +/* Entropy harvesting routine. This is supposed to be fast; do + * not do anything slow in here! + */ +static void +random_harvest_internal(u_int64_t somecounter, const void *entropy, + u_int count, u_int bits, u_int frac, enum esource origin) +{ + struct harvest *event; + + /* Lock the particular fifo */ + mtx_lock_spin(&harvestfifo[origin].lock); + + /* + * Don't make the harvest queues too big - help to prevent low-grade + * entropy swamping + */ + if (harvestfifo[origin].count < RANDOM_FIFO_MAX) { + + /* Lock the empty event buffer fifo */ + mtx_lock_spin(&emptyfifo.lock); + + if (!STAILQ_EMPTY(&emptyfifo.head)) { + event = STAILQ_FIRST(&emptyfifo.head); + STAILQ_REMOVE_HEAD(&emptyfifo.head, next); + } else + event = NULL; + + mtx_unlock_spin(&emptyfifo.lock); + + /* If we didn't obtain a buffer, tough */ + if (event) { + + /* Add the harvested data to the fifo */ + harvestfifo[origin].count++; + event->somecounter = somecounter; + event->size = count; + event->bits = bits; + event->frac = frac; + event->source = origin; + + /* XXXX Come back and make this dynamic! */ + count = MIN(count, HARVESTSIZE); + memcpy(event->entropy, entropy, count); + + STAILQ_INSERT_TAIL(&harvestfifo[origin].head, + event, next); + } + } + mtx_unlock_spin(&harvestfifo[origin].lock); + +} + +void +random_yarrow_write(void *buf, int count) +{ + int i; + u_int chunk; + + /* + * Break the input up into HARVESTSIZE chunks. The writer has too + * much control here, so "estimate" the the entropy as zero. + */ + for (i = 0; i < count; i += HARVESTSIZE) { + chunk = HARVESTSIZE; + if (i + chunk >= count) + chunk = (u_int)(count - i); + random_harvest_internal(get_cyclecount(), (char *)buf + i, + chunk, 0, 0, RANDOM_WRITE); + } +} + +void +random_yarrow_unblock(void) +{ + if (!random_systat.seeded) { + random_systat.seeded = 1; + selwakeuppri(&random_systat.rsel, PUSER); + wakeup(&random_systat); + } +} diff --git a/sys/dev/random/randomdev_soft.h b/sys/dev/random/randomdev_soft.h new file mode 100644 index 000000000000..46bb006f4664 --- /dev/null +++ b/sys/dev/random/randomdev_soft.h @@ -0,0 +1,93 @@ +/*- + * Copyright (c) 2000-2004 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$ + */ + +/* This header contains only those definitions that are global + * and harvester-specific for the entropy processor + */ + +/* #define ENTROPYSOURCE nn entropy sources (actually classes) + * This is properly defined in + * an enum in sys/random.h + */ + +/* Cryptographic block size in bits */ +#define BLOCKSIZE 256 + +/* The ring size _MUST_ be a power of 2 */ +#define HARVEST_RING_SIZE 1024 /* harvest ring buffer size */ +#define HARVEST_RING_MASK (HARVEST_RING_SIZE - 1) + +#define HARVESTSIZE 16 /* max size of each harvested entropy unit */ + +MALLOC_DECLARE(M_ENTROPY); + +/* These are used to queue harvested packets of entropy. The entropy + * buffer size is pretty arbitrary. + */ +struct harvest { + uintmax_t somecounter; /* fast counter for clock jitter */ + u_char entropy[HARVESTSIZE]; /* the harvested entropy */ + u_int size, bits, frac; /* stats about the entropy */ + enum esource source; /* stats about the entropy */ + STAILQ_ENTRY(harvest) next; /* next item on the list */ +}; + +void random_yarrow_init(void); +void random_yarrow_deinit(void); + +int random_yarrow_read(void *, int); +void random_yarrow_write(void *, int); + +void random_yarrow_init_harvester(void (*)(u_int64_t, const void *, u_int, + u_int, u_int, enum esource), int (*)(void *, int)); +void random_yarrow_deinit_harvester(void); + +void random_set_wakeup_exit(void *); +void random_process_event(struct harvest *event); +void random_yarrow_reseed(void); +void random_yarrow_unblock(void); + +void random_yarrow_init_alg(struct sysctl_ctx_list *, struct sysctl_oid *); +void random_yarrow_deinit_alg(void); + +extern struct random_systat random_yarrow; + +/* If this was c++, this would be a template */ +#define RANDOM_CHECK_UINT(name, min, max) \ +static int \ +random_check_uint_##name(SYSCTL_HANDLER_ARGS) \ +{ \ + if (oidp->oid_arg1 != NULL) { \ + if (*(u_int *)(oidp->oid_arg1) <= (min)) \ + *(u_int *)(oidp->oid_arg1) = (min); \ + else if (*(u_int *)(oidp->oid_arg1) > (max)) \ + *(u_int *)(oidp->oid_arg1) = (max); \ + } \ + return sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, \ + req); \ +} diff --git a/sys/dev/random/yarrow.c b/sys/dev/random/yarrow.c index 9d4bf03a09d2..ae22046925b0 100644 --- a/sys/dev/random/yarrow.c +++ b/sys/dev/random/yarrow.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000, 2001, 2002, 2003 Mark R V Murray + * Copyright (c) 2000-2004 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,7 +41,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include #include RANDOM_CHECK_UINT(gengateinterval, 4, 64); @@ -53,23 +53,6 @@ RANDOM_CHECK_UINT(slowoverthresh, 1, 5); /* Structure holding the entropy state */ static struct random_state random_state; -SYSCTL_NODE(_kern_random, OID_AUTO, yarrow, CTLFLAG_RW, 0, "Yarrow Parameters"); -SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, gengateinterval, - CTLTYPE_INT|CTLFLAG_RW, &random_state.gengateinterval, 10, - random_check_uint_gengateinterval, "I", "Generator Gate Interval"); -SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, bins, - CTLTYPE_INT|CTLFLAG_RW, &random_state.bins, 10, - random_check_uint_bins, "I", "Execution time tuner"); -SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, fastthresh, - CTLTYPE_INT|CTLFLAG_RW, &random_state.pool[0].thresh, (3*BLOCKSIZE)/4, - random_check_uint_fastthresh, "I", "Fast reseed threshold"); -SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, slowthresh, - CTLTYPE_INT|CTLFLAG_RW, &random_state.pool[1].thresh, BLOCKSIZE, - random_check_uint_slowthresh, "I", "Slow reseed threshold"); -SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, slowoverthresh, - CTLTYPE_INT|CTLFLAG_RW, &random_state.slowoverthresh, 2, - random_check_uint_slowoverthresh, "I", "Slow over-threshold reseed"); - static void generator_gate(void); static void reseed(u_int); @@ -118,13 +101,56 @@ random_process_event(struct harvest *event) } void -random_init(void) +random_yarrow_init_alg(struct sysctl_ctx_list *clist, struct sysctl_oid *in_o) { int i; + struct sysctl_oid *o, *random_yarrow_o; /* Yarrow parameters. Do not adjust these unless you have * have a very good clue about what they do! */ + o = SYSCTL_ADD_NODE(clist, + SYSCTL_CHILDREN(in_o), + OID_AUTO, "yarrow", CTLFLAG_RW, 0, + "Yarrow Parameters"); + + random_yarrow_o = o; + + o = SYSCTL_ADD_PROC(clist, + SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO, + "gengateinterval", CTLTYPE_INT|CTLFLAG_RW, + &random_state.gengateinterval, 10, + random_check_uint_gengateinterval, "I", + "Generation gate interval"); + + o = SYSCTL_ADD_PROC(clist, + SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO, + "bins", CTLTYPE_INT|CTLFLAG_RW, + &random_state.bins, 10, + random_check_uint_bins, "I", + "Execution time tuner"); + + o = SYSCTL_ADD_PROC(clist, + SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO, + "fastthresh", CTLTYPE_INT|CTLFLAG_RW, + &random_state.pool[0].thresh, (3*BLOCKSIZE)/4, + random_check_uint_fastthresh, "I", + "Fast reseed threshold"); + + o = SYSCTL_ADD_PROC(clist, + SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO, + "slowthresh", CTLTYPE_INT|CTLFLAG_RW, + &random_state.pool[1].thresh, BLOCKSIZE, + random_check_uint_slowthresh, "I", + "Slow reseed threshold"); + + o = SYSCTL_ADD_PROC(clist, + SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO, + "slowoverthresh", CTLTYPE_INT|CTLFLAG_RW, + &random_state.slowoverthresh, 2, + random_check_uint_slowoverthresh, "I", + "Slow over-threshold reseed"); + random_state.gengateinterval = 10; random_state.bins = 10; random_state.pool[0].thresh = (3*BLOCKSIZE)/4; @@ -145,7 +171,7 @@ random_init(void) } void -random_deinit(void) +random_yarrow_deinit_alg(void) { mtx_destroy(&random_reseed_mtx); } @@ -236,12 +262,12 @@ reseed(u_int fastslow) mtx_unlock(&random_reseed_mtx); /* Unblock the device if it was blocked due to being unseeded */ - random_unblock(); + random_yarrow_unblock(); } /* Internal function to return processed entropy from the PRNG */ int -read_random_real(void *buf, int count) +random_yarrow_read(void *buf, int count) { static int cur = 0; static int gate = 1; @@ -289,7 +315,7 @@ read_random_real(void *buf, int count) retval = count; } else { - retval = cur < count ? cur : count; + retval = MIN(cur, count); memcpy(buf, &genval[(int)sizeof(random_state.counter) - cur], (size_t)retval); @@ -319,7 +345,7 @@ generator_gate(void) /* Helper routine to perform explicit reseeds */ void -random_reseed(void) +random_yarrow_reseed(void) { reseed(SLOW); } diff --git a/sys/dev/random/yarrow.h b/sys/dev/random/yarrow.h index 2fc7be218cb1..558354d27f73 100644 --- a/sys/dev/random/yarrow.h +++ b/sys/dev/random/yarrow.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000 Mark R V Murray + * Copyright (c) 2000-2004 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/sys/modules/random/Makefile b/sys/modules/random/Makefile index 1e7286892624..9eee82168d07 100644 --- a/sys/modules/random/Makefile +++ b/sys/modules/random/Makefile @@ -5,7 +5,9 @@ .PATH: ${.CURDIR}/../../crypto/sha2 KMOD= random -SRCS= randomdev.c yarrow.c hash.c +SRCS= randomdev.c probe.c +SRCS+= nehemiah.c +SRCS+= randomdev_soft.c yarrow.c hash.c SRCS+= rijndael-alg-fst.c rijndael-api-fst.c sha2.c SRCS+= bus_if.h device_if.h vnode_if.h -- cgit v1.3