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:
parent
a8343c86d2
commit
f8530155da
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/projects/random_number_generator/; revision=254927
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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) \
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user