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.
This commit is contained in:
parent
a9b8e8be5d
commit
ad4dd3b5a2
@ -38,10 +38,7 @@
|
||||
|
||||
#include <machine/cpu.h>
|
||||
|
||||
#include <crypto/blowfish/blowfish.h>
|
||||
|
||||
#include <dev/random/hash.h>
|
||||
#include <dev/random/yarrow.h>
|
||||
#include <dev/random/randomdev.h>
|
||||
|
||||
static u_int read_random_phony(void *, u_int);
|
||||
|
||||
|
@ -33,19 +33,17 @@
|
||||
#include <sys/random.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <crypto/blowfish/blowfish.h>
|
||||
#include <crypto/rijndael/rijndael.h>
|
||||
|
||||
#include <dev/random/hash.h>
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Initialise the encryption routine by setting up the key schedule */
|
||||
void
|
||||
yarrow_encrypt_init(struct yarrowkey *context, void *data, size_t size)
|
||||
{
|
||||
size_t count;
|
||||
|
||||
count = size > KEYSIZE ? KEYSIZE : size;
|
||||
BF_set_key(&context->key, count, data);
|
||||
}
|
||||
|
||||
/* Encrypt the supplied data using the key schedule preset in the context */
|
||||
void
|
||||
yarrow_encrypt(struct yarrowkey *context, void *d_in, void *d_out, size_t size)
|
||||
{
|
||||
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;
|
||||
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
|
||||
* from the supplied /key/ which must be KEYSIZE bytes of binary
|
||||
* data.
|
||||
*/
|
||||
void
|
||||
yarrow_encrypt_init(struct yarrowkey *context, void *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.
|
||||
* KEYSIZE bytes are encrypted from /d_in/ to /d_out/.
|
||||
*/
|
||||
void
|
||||
yarrow_encrypt(struct yarrowkey *context, void *d_in, void *d_out)
|
||||
{
|
||||
rijndael_blockEncrypt(&context->cipher, &context->key, d_in,
|
||||
KEYSIZE*8, d_out);
|
||||
}
|
||||
|
@ -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 *);
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/kthread.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
@ -41,23 +42,23 @@
|
||||
#include <sys/random.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/unistd.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/resource.h>
|
||||
#include <crypto/blowfish/blowfish.h>
|
||||
|
||||
#include <dev/random/hash.h>
|
||||
#include <dev/random/yarrow.h>
|
||||
#include <dev/random/randomdev.h>
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
/* For use with make_dev(9)/destroy_dev(9). */
|
||||
static dev_t random_dev;
|
||||
static dev_t urandom_dev; /* XXX Temporary */
|
||||
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);
|
||||
|
||||
/* To stash the sysctl's until they are removed */
|
||||
static struct sysctl_oid *random_sysctl[12]; /* magic # is sysctl count */
|
||||
static int sysctlcount = 0;
|
||||
/* 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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
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");
|
||||
/* This can be turned off by the very paranoid
|
||||
* a reseed will turn it back on.
|
||||
*/
|
||||
random_systat.seeded = 1;
|
||||
|
||||
/* 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: <entropy source>\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);
|
||||
}
|
||||
}
|
||||
|
83
sys/dev/random/randomdev.h
Normal file
83
sys/dev/random/randomdev.h
Normal file
@ -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); \
|
||||
}
|
@ -29,229 +29,128 @@
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/kthread.h>
|
||||
#include <sys/libkern.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/selinfo.h>
|
||||
#include <sys/random.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/unistd.h>
|
||||
|
||||
#include <machine/atomic.h>
|
||||
#include <machine/cpu.h>
|
||||
|
||||
#include <crypto/blowfish/blowfish.h>
|
||||
#include <crypto/rijndael/rijndael.h>
|
||||
|
||||
#include <dev/random/hash.h>
|
||||
#include <dev/random/randomdev.h>
|
||||
#include <dev/random/yarrow.h>
|
||||
|
||||
/* #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);
|
||||
|
||||
static void random_kthread(void *);
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Initialise the fast and slow entropy pools */
|
||||
for (i = 0; i < 2; i++)
|
||||
yarrow_hash_init(&random_state.pool[i].hash);
|
||||
|
||||
/* Clear the counter */
|
||||
for (i = 0; i < 4; i++)
|
||||
random_state.counter[i] = 0;
|
||||
|
||||
/* Set up a lock for the reseed process */
|
||||
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;
|
||||
|
||||
/* Register the randomness harvesting routine */
|
||||
random_init_harvester(random_harvest_internal, read_random_real);
|
||||
|
||||
#ifdef DEBUG
|
||||
mtx_lock(&Giant);
|
||||
printf("Random initialise finish\n");
|
||||
mtx_unlock(&Giant);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user