1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-19 10:53:58 +00:00

Snapshot of current work;

1) Clean up namespace; only use "Yarrow" where it is Yarrow-specific
or close enough to the Yarrow algorithm. For the rest use a neutral
name.

2) Tidy up headers; put private stuff in private places. More could
be done here.

3) Streamline the hashing/encryption; no need for a 256-bit counter;
128 bits will last for long enough.

There are bits of debug code lying around; these will be removed
at a later stage.
This commit is contained in:
Mark Murray 2013-08-26 18:29:51 +00:00
parent a8343c86d2
commit f8530155da
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/random_number_generator/; revision=254927
7 changed files with 253 additions and 193 deletions

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2000-2004 Mark R V Murray
* Copyright (c) 2000-2013 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -60,7 +60,7 @@ static int (*read_func)(void *, int) = read_random_phony;
/* Initialise the harvester at load time */
void
random_yarrow_init_harvester(void (*reaper)(u_int64_t, const void *, u_int,
randomdev_init_harvester(void (*reaper)(u_int64_t, const void *, u_int,
u_int, u_int, enum esource), int (*reader)(void *, int))
{
reap_func = reaper;
@ -69,7 +69,7 @@ random_yarrow_init_harvester(void (*reaper)(u_int64_t, const void *, u_int,
/* Deinitialise the harvester at unload time */
void
random_yarrow_deinit_harvester(void)
randomdev_deinit_harvester(void)
{
reap_func = NULL;
read_func = read_random_phony;

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2000-2004 Mark R V Murray
* Copyright (c) 2000-2013 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -36,46 +36,46 @@ __FBSDID("$FreeBSD$");
#include <dev/random/hash.h>
/* initialise the hash */
/* Initialise the hash */
void
yarrow_hash_init(struct yarrowhash *context)
randomdev_hash_init(struct randomdev_hash *context)
{
SHA256_Init(&context->sha);
}
/* iterate the hash */
/* Iterate the hash */
void
yarrow_hash_iterate(struct yarrowhash *context, void *data, size_t size)
randomdev_hash_iterate(struct randomdev_hash *context, void *data, size_t size)
{
SHA256_Update(&context->sha, data, size);
}
/* Conclude by returning the hash in the supplied /buf/ which must be
/* Conclude by returning the hash in the supplied <*buf> which must be
* KEYSIZE bytes long.
*/
void
yarrow_hash_finish(struct yarrowhash *context, void *buf)
randomdev_hash_finish(struct randomdev_hash *context, void *buf)
{
SHA256_Final(buf, &context->sha);
}
/* Initialise the encryption routine by setting up the key schedule
* from the supplied /data/ which must be KEYSIZE bytes of binary
* data.
* from the supplied <*data> which must be KEYSIZE bytes of binary
* data. Use CBC mode for better avalanche.
*/
void
yarrow_encrypt_init(struct yarrowkey *context, void *data)
randomdev_encrypt_init(struct randomdev_key *context, void *data)
{
rijndael_cipherInit(&context->cipher, MODE_CBC, NULL);
rijndael_makeKey(&context->key, DIR_ENCRYPT, KEYSIZE*8, data);
}
/* Encrypt the supplied data using the key schedule preset in the context.
* KEYSIZE bytes are encrypted from /d_in/ to /d_out/.
* <length> bytes are encrypted from <*d_in> to <*d_out>. <length> must be
* a multiple of BLOCKSIZE.
*/
void
yarrow_encrypt(struct yarrowkey *context, void *d_in, void *d_out)
randomdev_encrypt(struct randomdev_key *context, void *d_in, void *d_out, unsigned length)
{
rijndael_blockEncrypt(&context->cipher, &context->key, d_in,
KEYSIZE*8, d_out);
rijndael_blockEncrypt(&context->cipher, &context->key, d_in, length*8, d_out);
}

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2000-2004 Mark R V Murray
* Copyright (c) 2000-2013 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -26,19 +26,20 @@
* $FreeBSD$
*/
#define KEYSIZE 32 /* (in bytes) 32 bytes == 256 bits */
#define KEYSIZE 32 /* (in bytes) == 256 bits */
#define BLOCKSIZE 16 /* (in bytes) == 128 bits */
struct yarrowhash { /* Big! Make static! */
struct randomdev_hash { /* Big! Make static! */
SHA256_CTX sha;
};
struct yarrowkey { /* Big! Make static! */
struct randomdev_key { /* Big! Make static! */
keyInstance key; /* Key schedule */
cipherInstance cipher; /* Rijndael internal */
};
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 *);
void yarrow_encrypt(struct yarrowkey *context, void *, void *);
void randomdev_hash_init(struct randomdev_hash *);
void randomdev_hash_iterate(struct randomdev_hash *, void *, size_t);
void randomdev_hash_finish(struct randomdev_hash *, void *);
void randomdev_encrypt_init(struct randomdev_key *, void *);
void randomdev_encrypt(struct randomdev_key *context, void *, void *, unsigned);

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2000-2009 Mark R V Murray
* Copyright (c) 2000-2013 Mark R V Murray
* Copyright (c) 2004 Robert N. M. Watson
* All rights reserved.
*
@ -26,6 +26,12 @@
*
*/
#if !defined(YARROW_RNG) && !defined(FORTUNA_RNG)
#define YARROW_RNG
#elif defined(YARROW_RNG) && defined(FORTUNA_RNG)
#error "Must define either YARROW_RNG or FORTUNA_RNG"
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@ -54,30 +60,56 @@ __FBSDID("$FreeBSD$");
#include <dev/random/random_adaptors.h>
#include <dev/random/randomdev.h>
#include <dev/random/randomdev_soft.h>
#if defined(YARROW_RNG)
#include <dev/random/yarrow.h>
#endif
#if defined(FORTUNA_RNG)
#include <dev/random/fortuna.h>
#endif
#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,
static void random_harvest_internal(u_int64_t, const void *, u_int,
u_int, u_int, enum esource);
static int random_yarrow_poll(int event,struct thread *td);
static int random_yarrow_block(int flag);
static void random_yarrow_flush_reseed(void);
static int randomdev_poll(int event, struct thread *td);
static int randomdev_block(int flag);
static void randomdev_flush_reseed(void);
struct random_adaptor random_yarrow = {
#if defined(YARROW_RNG)
static struct random_adaptor random_context = {
.ident = "Software, Yarrow",
.init = random_yarrow_init,
.deinit = random_yarrow_deinit,
.block = random_yarrow_block,
.init = randomdev_init,
.deinit = randomdev_deinit,
.block = randomdev_block,
.read = random_yarrow_read,
.write = random_yarrow_write,
.poll = random_yarrow_poll,
.reseed = random_yarrow_flush_reseed,
.seeded = 1,
.write = randomdev_write,
.poll = randomdev_poll,
.reseed = randomdev_flush_reseed,
.seeded = 0,
};
#define RANDOM_MODULE_NAME yarrow
#define RANDOM_CSPRNG_NAME "yarrow"
#endif
MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers");
#if defined(FORTUNA_RNG)
static struct random_adaptor random_context = {
.ident = "Software, Fortuna",
.init = randomdev_init,
.deinit = randomdev_deinit,
.block = randomdev_block,
.read = random_fortuna_read,
.write = randomdev_write,
.poll = randomdev_poll,
.reseed = randomdev_flush_reseed,
.seeded = 0,
};
#define RANDOM_MODULE_NAME fortuna
#define RANDOM_CSPRNG_NAME "fortuna"
#endif
MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers for " RANDOM_CSPRNG_NAME);
/*
* The harvest mutex protects the consistency of the entropy fifos and
@ -116,16 +148,20 @@ random_check_boolean(SYSCTL_HANDLER_ARGS)
return sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
}
/* ARGSUSED */
void
random_yarrow_init(void)
randomdev_init(void)
{
int error, i;
struct harvest *np;
struct sysctl_oid *random_sys_o, *random_sys_harvest_o;
enum esource e;
#if defined(YARROW_RNG)
random_yarrow_init_alg(&random_clist);
#endif
#if defined(FORTUNA_RNG)
random_fortuna_init_alg(&random_clist);
#endif
random_sys_o = SYSCTL_ADD_NODE(&random_clist,
SYSCTL_STATIC_CHILDREN(_kern_random),
@ -135,7 +171,7 @@ random_yarrow_init(void)
SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_sys_o),
OID_AUTO, "seeded", CTLTYPE_INT | CTLFLAG_RW,
&random_yarrow.seeded, 1, random_check_boolean, "I",
&random_context.seeded, 1, random_check_boolean, "I",
"Seeded State");
random_sys_harvest_o = SYSCTL_ADD_NODE(&random_clist,
@ -156,13 +192,18 @@ random_yarrow_init(void)
SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_sys_harvest_o),
OID_AUTO, "interrupt", CTLTYPE_INT | CTLFLAG_RW,
&harvest.interrupt, 1, random_check_boolean, "I",
&harvest.interrupt, 0, random_check_boolean, "I",
"Harvest IRQ entropy");
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");
SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_sys_harvest_o),
OID_AUTO, "namei", CTLTYPE_INT | CTLFLAG_RW,
&harvest.namei, 0, random_check_boolean, "I",
"Harvest namei cache entropy");
/* Initialise the harvest fifos */
STAILQ_INIT(&emptyfifo.head);
@ -180,24 +221,23 @@ random_yarrow_init(void)
/* Start the hash/reseed thread */
error = kproc_create(random_kthread, NULL,
&random_kthread_proc, RFHIGHPID, 0, "yarrow");
&random_kthread_proc, RFHIGHPID, 0, RANDOM_CSPRNG_NAME);
if (error != 0)
panic("Cannot create entropy maintenance thread.");
/* Register the randomness harvesting routine */
random_yarrow_init_harvester(random_harvest_internal,
random_yarrow_read);
randomdev_init_harvester(random_harvest_internal,
random_context.read);
}
/* ARGSUSED */
void
random_yarrow_deinit(void)
randomdev_deinit(void)
{
struct harvest *np;
enum esource e;
/* Deregister the randomness harvesting routine */
random_yarrow_deinit_harvester();
randomdev_deinit_harvester();
/*
* Command the hash/reseed thread to end and wait for it to finish
@ -219,7 +259,12 @@ random_yarrow_deinit(void)
}
}
#if defined(YARROW_RNG)
random_yarrow_deinit_alg();
#endif
#if defined(FORTUNA_RNG)
random_fortuna_deinit_alg();
#endif
mtx_destroy(&harvest_mtx);
@ -298,10 +343,7 @@ random_harvest_internal(u_int64_t somecounter, const void *entropy,
{
struct harvest *event;
KASSERT(origin == RANDOM_START || origin == RANDOM_WRITE ||
origin == RANDOM_KEYBOARD || origin == RANDOM_MOUSE ||
origin == RANDOM_NET || origin == RANDOM_INTERRUPT ||
origin == RANDOM_PURE,
KASSERT(origin >= RANDOM_START && origin <= RANDOM_PURE,
("random_harvest_internal: origin %d invalid\n", origin));
/* Lockless read to avoid lock operations if fifo is full. */
@ -311,12 +353,13 @@ random_harvest_internal(u_int64_t somecounter, const void *entropy,
mtx_lock_spin(&harvest_mtx);
/*
* Don't make the harvest queues too big - help to prevent low-grade
* Don't make the harvest queues too big - help to thwart low-grade
* entropy swamping
*/
if (harvestfifo[origin].count < RANDOM_FIFO_MAX) {
event = STAILQ_FIRST(&emptyfifo.head);
if (event != NULL) {
count = MIN(count, HARVESTSIZE);
/* Add the harvested data to the fifo */
STAILQ_REMOVE_HEAD(&emptyfifo.head, next);
harvestfifo[origin].count++;
@ -326,10 +369,20 @@ random_harvest_internal(u_int64_t somecounter, const void *entropy,
event->frac = frac;
event->source = origin;
/* XXXX Come back and make this dynamic! */
count = MIN(count, HARVESTSIZE);
memcpy(event->entropy, entropy, count);
#if 1
{
int i;
printf("Harvest:%16jX ", event->somecounter);
for (i = 0; i < event->size; i++)
printf("%02X", event->entropy[i]);
for (; i < 16; i++)
printf(" ");
printf(" %2d 0x%2X.%03X %02X\n", event->size, event->bits, event->frac, event->source);
}
#endif
STAILQ_INSERT_TAIL(&harvestfifo[origin].head,
event, next);
}
@ -338,7 +391,7 @@ random_harvest_internal(u_int64_t somecounter, const void *entropy,
}
void
random_yarrow_write(void *buf, int count)
randomdev_write(void *buf, int count)
{
int i;
u_int chunk;
@ -357,46 +410,46 @@ random_yarrow_write(void *buf, int count)
}
void
random_yarrow_unblock(void)
randomdev_unblock(void)
{
if (!random_yarrow.seeded) {
random_yarrow.seeded = 1;
selwakeuppri(&random_yarrow.rsel, PUSER);
wakeup(&random_yarrow);
if (!random_context.seeded) {
random_context.seeded = 1;
selwakeuppri(&random_context.rsel, PUSER);
wakeup(&random_context);
}
(void)atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_NONE,
ARC4_ENTR_HAVE);
}
static int
random_yarrow_poll(int events, struct thread *td)
randomdev_poll(int events, struct thread *td)
{
int revents = 0;
mtx_lock(&random_reseed_mtx);
if (random_yarrow.seeded)
if (random_context.seeded)
revents = events & (POLLIN | POLLRDNORM);
else
selrecord(td, &random_yarrow.rsel);
selrecord(td, &random_context.rsel);
mtx_unlock(&random_reseed_mtx);
return revents;
}
static int
random_yarrow_block(int flag)
randomdev_block(int flag)
{
int error = 0;
mtx_lock(&random_reseed_mtx);
/* Blocking logic */
while (!random_yarrow.seeded && !error) {
while (!random_context.seeded && !error) {
if (flag & O_NONBLOCK)
error = EWOULDBLOCK;
else {
printf("Entropy device is blocking.\n");
error = msleep(&random_yarrow,
error = msleep(&random_context,
&random_reseed_mtx,
PUSER | PCATCH, "block", 0);
}
@ -408,23 +461,28 @@ random_yarrow_block(int flag)
/* Helper routine to perform explicit reseeds */
static void
random_yarrow_flush_reseed(void)
randomdev_flush_reseed(void)
{
/* Command a entropy queue flush and wait for it to finish */
random_kthread_control = 1;
while (random_kthread_control)
pause("-", hz / 10);
#if defined(YARROW_RNG)
random_yarrow_reseed();
#endif
#if defined(FORTUNA_RNG)
random_fortuna_reseed();
#endif
}
static int
yarrow_modevent(module_t mod, int type, void *unused)
randomdev_modevent(module_t mod, int type, void *unused)
{
switch (type) {
case MOD_LOAD:
random_adaptor_register("yarrow", &random_yarrow);
random_adaptor_register(RANDOM_CSPRNG_NAME, &random_context);
/*
* For statically built kernels that contain both device
* random and options PADLOCK_RNG/RDRAND_RNG/etc..,
@ -437,11 +495,11 @@ yarrow_modevent(module_t mod, int type, void *unused)
* (by dependency). This event handler is there to delay
* creation of /dev/{u,}random and attachment of this *_rng.ko.
*/
EVENTHANDLER_INVOKE(random_adaptor_attach, &random_yarrow);
EVENTHANDLER_INVOKE(random_adaptor_attach, &random_context);
return (0);
}
return (EINVAL);
}
RANDOM_ADAPTOR_MODULE(yarrow, yarrow_modevent, 1);
RANDOM_ADAPTOR_MODULE(RANDOM_MODULE_NAME, randomdev_modevent, 1);

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2000-2004 Mark R V Murray
* Copyright (c) 2000-2013 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -35,9 +35,6 @@
* 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)
@ -51,34 +48,28 @@ MALLOC_DECLARE(M_ENTROPY);
*/
struct harvest {
uintmax_t somecounter; /* fast counter for clock jitter */
u_char entropy[HARVESTSIZE]; /* the harvested entropy */
uint8_t 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);
void randomdev_init(void);
void randomdev_deinit(void);
int random_yarrow_read(void *, int);
void random_yarrow_write(void *, int);
void randomdev_write(void *, int);
void random_yarrow_init_harvester(void (*)(u_int64_t, const void *, u_int,
void randomdev_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 randomdev_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 randomdev_unblock(void);
void random_yarrow_init_alg(struct sysctl_ctx_list *);
void random_yarrow_deinit_alg(void);
extern struct random_adaptor random_yarrow;
extern struct mtx random_reseed_mtx;
/* If this was c++, this would be a template */
/* If this was C++, the macro below would be a template */
#define RANDOM_CHECK_UINT(name, min, max) \
static int \
random_check_uint_##name(SYSCTL_HANDLER_ARGS) \

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2000-2004 Mark R V Murray
* Copyright (c) 2000-2013 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -45,21 +45,68 @@ __FBSDID("$FreeBSD$");
#include <dev/random/randomdev_soft.h>
#include <dev/random/yarrow.h>
#define TIMEBIN 16 /* max value for Pt/t */
#define FAST 0
#define SLOW 1
/* This is the beastie that needs protecting. It contains all of the
* state that we are excited about.
* Exactly one is instantiated.
*/
static struct random_state {
union {
uint8_t byte[BLOCKSIZE];
uint64_t qword[BLOCKSIZE/sizeof(uint64_t)];
} counter; /* C */
struct randomdev_key key; /* K */
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 {
u_int bits; /* estimated bits of entropy */
u_int frac; /* fractional bits of entropy
(given as 1024/n) */
} source[ENTROPYSOURCE];
u_int thresh; /* pool reseed threshhold */
struct randomdev_hash hash; /* accumulated entropy */
} pool[2]; /* pool[0] is fast, pool[1] is slow */
u_int which; /* toggle - sets the current insertion pool */
} random_state;
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(fastthresh, (BLOCKSIZE*8)/4, (BLOCKSIZE*8)); /* Bit counts */
RANDOM_CHECK_UINT(slowthresh, (BLOCKSIZE*8)/4, (BLOCKSIZE*8)); /* Bit counts */
RANDOM_CHECK_UINT(slowoverthresh, 1, 5);
/* Structure holding the entropy state */
static struct random_state random_state;
static void generator_gate(void);
static void reseed(u_int);
/* The reseed thread mutex */
struct mtx random_reseed_mtx;
/* 128-bit C = 0 */
/* Nothing to see here, folks, just an ugly mess. */
static void
clear_counter(void)
{
random_state.counter.qword[0] = 0UL;
random_state.counter.qword[1] = 0UL;
}
/* 128-bit C = C + 1 */
/* Nothing to see here, folks, just an ugly mess. */
static void
increment_counter(void)
{
random_state.counter.qword[0]++;
if (!random_state.counter.qword[0])
random_state.counter.qword[1]++;
}
/* Process a single stochastic event off the harvest queue */
void
random_process_event(struct harvest *event)
@ -71,13 +118,13 @@ random_process_event(struct harvest *event)
/* 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,
randomdev_hash_iterate(&random_state.pool[pl].hash, event->entropy,
sizeof(event->entropy));
yarrow_hash_iterate(&random_state.pool[pl].hash, &event->somecounter,
randomdev_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;
source->bits += event->bits + (source->frac >> 12); /* bits + frac/0x1000 */
source->frac &= 0xFFF; /* Keep the fractional bits */
/* Count the over-threshold sources in each pool */
for (pl = 0; pl < 2; pl++) {
@ -132,14 +179,14 @@ random_yarrow_init_alg(struct sysctl_ctx_list *clist)
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_state.pool[0].thresh, (3*(BLOCKSIZE*8))/4,
random_check_uint_fastthresh, "I",
"Fast reseed threshold");
SYSCTL_ADD_PROC(clist,
SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
"slowthresh", CTLTYPE_INT|CTLFLAG_RW,
&random_state.pool[1].thresh, BLOCKSIZE,
&random_state.pool[1].thresh, (BLOCKSIZE*8),
random_check_uint_slowthresh, "I",
"Slow reseed threshold");
@ -152,21 +199,20 @@ random_yarrow_init_alg(struct sysctl_ctx_list *clist)
random_state.gengateinterval = 10;
random_state.bins = 10;
random_state.pool[0].thresh = (3*BLOCKSIZE)/4;
random_state.pool[1].thresh = BLOCKSIZE;
random_state.pool[0].thresh = (3*(BLOCKSIZE*8))/4;
random_state.pool[1].thresh = (BLOCKSIZE*8);
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);
randomdev_hash_init(&random_state.pool[i].hash);
/* Clear the counter */
for (i = 0; i < 4; i++)
random_state.counter[i] = 0;
clear_counter();
/* Set up a lock for the reseed process */
mtx_init(&random_reseed_mtx, "random reseed", NULL, MTX_DEF);
mtx_init(&random_reseed_mtx, "Yarrow reseed", NULL, MTX_DEF);
}
void
@ -181,10 +227,10 @@ reseed(u_int fastslow)
/* Interrupt-context stack is a limited resource; make large
* structures static.
*/
static u_char v[TIMEBIN][KEYSIZE]; /* v[i] */
static struct yarrowhash context;
u_char hash[KEYSIZE]; /* h' */
u_char temp[KEYSIZE];
static uint8_t v[TIMEBIN][KEYSIZE]; /* v[i] */
static struct randomdev_hash context;
uint8_t hash[KEYSIZE]; /* h' */
uint8_t temp[KEYSIZE];
u_int i;
enum esource j;
@ -193,15 +239,15 @@ reseed(u_int fastslow)
/* 1. Hash the accumulated entropy into v[0] */
yarrow_hash_init(&context);
randomdev_hash_init(&context);
/* Feed the slow pool hash in if slow */
if (fastslow == SLOW)
yarrow_hash_iterate(&context,
randomdev_hash_iterate(&context,
&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]);
sizeof(struct randomdev_hash));
randomdev_hash_iterate(&context,
&random_state.pool[FAST].hash, sizeof(struct randomdev_hash));
randomdev_hash_finish(&context, v[0]);
/* 2. Compute hash values for all v. _Supposed_ to be computationally
* intensive.
@ -210,34 +256,33 @@ reseed(u_int fastslow)
if (random_state.bins > TIMEBIN)
random_state.bins = TIMEBIN;
for (i = 1; i < random_state.bins; i++) {
yarrow_hash_init(&context);
randomdev_hash_init(&context);
/* v[i] #= h(v[i - 1]) */
yarrow_hash_iterate(&context, v[i - 1], KEYSIZE);
randomdev_hash_iterate(&context, v[i - 1], KEYSIZE);
/* v[i] #= h(v[0]) */
yarrow_hash_iterate(&context, v[0], KEYSIZE);
randomdev_hash_iterate(&context, v[0], KEYSIZE);
/* v[i] #= h(i) */
yarrow_hash_iterate(&context, &i, sizeof(u_int));
randomdev_hash_iterate(&context, &i, sizeof(u_int));
/* Return the hashval */
yarrow_hash_finish(&context, v[i]);
randomdev_hash_finish(&context, v[i]);
}
/* 3. Compute a new key; h' is the identity function here;
* it is not being ignored!
*/
yarrow_hash_init(&context);
yarrow_hash_iterate(&context, &random_state.key, KEYSIZE);
randomdev_hash_init(&context);
randomdev_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);
randomdev_hash_iterate(&context, &v[i], KEYSIZE);
randomdev_hash_finish(&context, temp);
randomdev_encrypt_init(&random_state.key, temp);
/* 4. Recompute the 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));
clear_counter();
randomdev_encrypt(&random_state.key, random_state.counter.byte, temp, BLOCKSIZE);
memcpy(random_state.counter.byte, temp, BLOCKSIZE);
/* 5. Reset entropy estimate accumulators to zero */
@ -258,7 +303,7 @@ reseed(u_int fastslow)
/* XXX Not done here yet */
/* Unblock the device if it was blocked due to being unseeded */
random_yarrow_unblock();
randomdev_unblock();
/* Release the reseed mutex */
mtx_unlock(&random_reseed_mtx);
@ -270,7 +315,7 @@ random_yarrow_read(void *buf, int count)
{
static int cur = 0;
static int gate = 1;
static u_char genval[KEYSIZE];
static uint8_t genval[KEYSIZE];
size_t tomove;
int i;
int retval;
@ -283,16 +328,14 @@ random_yarrow_read(void *buf, int count)
random_state.outputblocks = 0;
gate = 0;
}
if (count > 0 && (size_t)count >= sizeof(random_state.counter)) {
if (count > 0 && (size_t)count >= BLOCKSIZE) {
retval = 0;
for (i = 0; i < count; i += (int)sizeof(random_state.counter)) {
random_state.counter[0]++;
yarrow_encrypt(&random_state.key, random_state.counter,
genval);
tomove = min(count - i, sizeof(random_state.counter));
for (i = 0; i < count; i += BLOCKSIZE) {
increment_counter();
randomdev_encrypt(&random_state.key, random_state.counter.byte, genval, BLOCKSIZE);
tomove = MIN(count - i, BLOCKSIZE);
memcpy((char *)buf + i, genval, tomove);
if (++random_state.outputblocks >=
random_state.gengateinterval) {
if (++random_state.outputblocks >= random_state.gengateinterval) {
generator_gate();
random_state.outputblocks = 0;
}
@ -302,13 +345,11 @@ random_yarrow_read(void *buf, int count)
}
else {
if (!cur) {
random_state.counter[0]++;
yarrow_encrypt(&random_state.key, random_state.counter,
genval);
increment_counter();
randomdev_encrypt(&random_state.key, random_state.counter.byte, genval, BLOCKSIZE);
memcpy(buf, genval, (size_t)count);
cur = (int)sizeof(random_state.counter) - count;
if (++random_state.outputblocks >=
random_state.gengateinterval) {
cur = BLOCKSIZE - count;
if (++random_state.outputblocks >= random_state.gengateinterval) {
generator_gate();
random_state.outputblocks = 0;
}
@ -316,9 +357,7 @@ random_yarrow_read(void *buf, int count)
}
else {
retval = MIN(cur, count);
memcpy(buf,
&genval[(int)sizeof(random_state.counter) - cur],
(size_t)retval);
memcpy(buf, &genval[BLOCKSIZE - cur], (size_t)retval);
cur -= retval;
}
}
@ -330,17 +369,15 @@ static void
generator_gate(void)
{
u_int i;
u_char temp[KEYSIZE];
uint8_t temp[KEYSIZE];
for (i = 0; i < KEYSIZE; i += sizeof(random_state.counter)) {
random_state.counter[0]++;
yarrow_encrypt(&random_state.key, random_state.counter,
&(temp[i]));
for (i = 0; i < KEYSIZE; i += BLOCKSIZE) {
increment_counter();
randomdev_encrypt(&random_state.key, random_state.counter.byte, temp + i, BLOCKSIZE);
}
yarrow_encrypt_init(&random_state.key, temp);
randomdev_encrypt_init(&random_state.key, temp);
memset((void *)temp, 0, KEYSIZE);
}
/* Helper routine to perform explicit reseeds */

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2000-2004 Mark R V Murray
* Copyright (c) 2000-2013 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -26,34 +26,7 @@
* $FreeBSD$
*/
/* This contains Yarrow-specific declarations.
* See http://www.counterpane.com/yarrow.html
*/
#define TIMEBIN 16 /* max value for Pt/t */
#define FAST 0
#define SLOW 1
/* 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[4]; /* C - 256 bits */
struct yarrowkey key; /* K */
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 {
u_int bits; /* estimated bits of entropy */
u_int frac; /* fractional bits of entropy
(given as 1024/n) */
} source[ENTROPYSOURCE];
u_int thresh; /* pool reseed threshhold */
struct yarrowhash hash; /* accumulated entropy */
} pool[2]; /* pool[0] is fast, pool[1] is slow */
u_int which; /* toggle - sets the current insertion pool */
};
void random_yarrow_init_alg(struct sysctl_ctx_list *);
void random_yarrow_deinit_alg(void);
int random_yarrow_read(void *, int);
void random_yarrow_reseed(void);