Bring in some behind-the-scenes development, mainly By Arthur Mesh,

the rest by me.

o Namespace cleanup; the Yarrow name is now restricted to where it
  really applies; this is in anticipation of being augmented or
  replaced by Fortuna in the future. Fortuna is mentioned, but behind
  #if logic, and is ignorable for now.

o The harvest queue is pulled out into its own modules.

o Entropy harvesting is emproved, both by being made more conservative,
  and by separating (a bit!) the sources. Available entropy crumbs are
  marginally improved.

o Selection of sources is made clearer. With recent revelations,
  this will receive more work in the weeks and months to come.

Submitted by:	 Arthur Mesh (partly) <arthurmesh@gmail.com>
This commit is contained in:
markm 2013-09-07 14:15:13 +00:00
commit 42ac52f951
30 changed files with 890 additions and 428 deletions

View File

@ -67,6 +67,6 @@
# $FreeBSD$
#
SUBDIR= cdev dyn_sysctl firmware khelp syscall
SUBDIR= cdev dyn_sysctl firmware khelp random_adaptor syscall
.include <bsd.subdir.mk>

View File

@ -0,0 +1,6 @@
# $FreeBSD$
KMOD= random_adaptor_example
SRCS= ${KMOD}.c
.include <bsd.kmod.mk>

View File

@ -0,0 +1,94 @@
/*-
* Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/selinfo.h>
#include <sys/systm.h>
#include <dev/random/random_adaptors.h>
#include <dev/random/randomdev.h>
#define RNG_NAME "example"
static int random_example_read(void *, int);
struct random_adaptor random_example = {
.ident = "Example RNG",
.init = (random_init_func_t *)random_null_func,
.deinit = (random_deinit_func_t *)random_null_func,
.read = random_example_read,
.write = (random_write_func_t *)random_null_func,
.reseed = (random_reseed_func_t *)random_null_func,
.seeded = 1,
};
/*
* Used under the license provided @ http://xkcd.com/221/
* http://creativecommons.org/licenses/by-nc/2.5/
*/
static u_char
getRandomNumber(void)
{
return 4; /* chosen by fair dice roll, guaranteed to be random */
}
static int
random_example_read(void *buf, int c)
{
u_char *b;
int count;
b = buf;
for (count = 0; count < c; count++) {
b[count] = getRandomNumber();
}
printf("returning %d bytes of pure randomness\n", c);
return (c);
}
static int
random_example_modevent(module_t mod, int type, void *unused)
{
switch (type) {
case MOD_LOAD:
random_adaptor_register(RNG_NAME, &random_example);
EVENTHANDLER_INVOKE(random_adaptor_attach, &random_example);
return (0);
}
return (EINVAL);
}
RANDOM_ADAPTOR_MODULE(random_example, random_example_modevent, 1);

View File

@ -2042,8 +2042,9 @@ rt2860.fw optional rt2860fw | ralfw \
clean "rt2860.fw"
dev/random/harvest.c standard
dev/random/hash.c optional random
dev/random/probe.c optional random
dev/random/pseudo_rng.c standard
dev/random/random_adaptors.c standard
dev/random/random_harvestq.c standard
dev/random/randomdev.c optional random
dev/random/randomdev_soft.c optional random
dev/random/yarrow.c optional random

View File

@ -476,7 +476,7 @@ glxsb_rnd(void *v)
if (status & SB_RNS_TRNG_VALID) {
value = bus_read_4(sc->sc_sr, SB_RANDOM_NUM);
/* feed with one uint32 */
random_harvest(&value, 4, 32, 0, RANDOM_PURE);
random_harvest(&value, 4, 32/2, 0, RANDOM_PURE);
}
callout_reset(&sc->sc_rngco, sc->sc_rnghz, glxsb_rnd, sc);

View File

@ -258,7 +258,7 @@ hifn_partname(struct hifn_softc *sc)
static void
default_harvest(struct rndtest_state *rsp, void *buf, u_int count)
{
random_harvest(buf, count, count*NBBY, 0, RANDOM_PURE);
random_harvest(buf, count, count*NBBY/2, 0, RANDOM_PURE);
}
static u_int

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);

119
sys/dev/random/pseudo_rng.c Normal file
View File

@ -0,0 +1,119 @@
/*-
* Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/time.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/selinfo.h>
#include <sys/systm.h>
#include <dev/random/random_adaptors.h>
#include <dev/random/randomdev.h>
static struct mtx pseudo_random_block_mtx;
static int
pseudo_random_block_read(void *buf __unused, int c __unused)
{
mtx_lock(&pseudo_random_block_mtx);
printf("random(4) device is blocking.\n");
msleep(pseudo_random_block_read, &pseudo_random_block_mtx, 0,
"block", 0);
mtx_unlock(&pseudo_random_block_mtx);
return (0);
}
static void
pseudo_random_block_init(void)
{
mtx_init(&pseudo_random_block_mtx, "sleep mtx for random_block",
NULL, MTX_DEF);
}
static void
pseudo_random_block_deinit(void)
{
mtx_destroy(&pseudo_random_block_mtx);
}
struct random_adaptor pseudo_random_block = {
.ident = "pseudo-RNG that always blocks",
.init = pseudo_random_block_init,
.deinit = pseudo_random_block_deinit,
.read = pseudo_random_block_read,
.write = (random_write_func_t *)random_null_func,
.reseed = (random_reseed_func_t *)random_null_func,
.seeded = 1,
};
static int
pseudo_random_panic_read(void *buf, int c)
{
panic("Insert a witty panic msg in here.");
return (0);
}
struct random_adaptor pseudo_random_panic = {
.ident = "pseudo-RNG that always panics on first read(2)",
.init = (random_init_func_t *)random_null_func,
.deinit = (random_deinit_func_t *)random_null_func,
.read = pseudo_random_panic_read,
.write = (random_write_func_t *)random_null_func,
.reseed = (random_reseed_func_t *)random_null_func,
.seeded = 1,
};
static int
pseudo_random_modevent(module_t mod, int type, void *unused)
{
switch (type) {
case MOD_LOAD:
random_adaptor_register("block", &pseudo_random_block);
EVENTHANDLER_INVOKE(random_adaptor_attach,
&pseudo_random_block);
random_adaptor_register("panic", &pseudo_random_panic);
return (0);
}
return (EINVAL);
}
RANDOM_ADAPTOR_MODULE(pseudo, pseudo_random_modevent, 1);

View File

@ -1,6 +1,7 @@
/*-
* Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
* Copyright (c) 2013 David E. O'Brien <obrien@NUXI.org>
* Copyright (c) 2004 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -30,16 +31,20 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/kthread.h>
#include <sys/lock.h>
#include <sys/random.h>
#include <sys/selinfo.h>
#include <sys/sysctl.h>
#include <sys/sx.h>
#include <sys/malloc.h>
#include <sys/queue.h>
#include <sys/libkern.h>
#include <sys/unistd.h>
#include <dev/random/random_adaptors.h>
#include <dev/random/randomdev.h>
#include <dev/random/randomdev_soft.h>
#include <dev/random/random_adaptors.h>
LIST_HEAD(adaptors_head, random_adaptors);
static struct adaptors_head adaptors = LIST_HEAD_INITIALIZER(adaptors);
@ -57,7 +62,8 @@ random_adaptor_register(const char *name, struct random_adaptor *rsp)
KASSERT(name != NULL && rsp != NULL, ("invalid input to %s", __func__));
rpp = malloc(sizeof(struct random_adaptors), M_RANDOM_ADAPTORS, M_WAITOK);
rpp = malloc(sizeof(struct random_adaptors), M_RANDOM_ADAPTORS,
M_WAITOK);
rpp->name = name;
rpp->rsp = rsp;
@ -87,6 +93,93 @@ random_adaptor_get(const char *name)
return (rsp);
}
/*
* In the past, the logic of the random_adaptor selection was inverted, such
* that hardware RNGs would be chosen unless disabled. This routine is here to
* preserve that functionality to avoid folks losing their hardware RNGs by
* upgrading to newer kernel.
*/
static void
random_adaptor_choose_legacy(struct random_adaptor **adaptor)
{
struct random_adaptor *tmp;
int enable;
/* Then go looking for hardware */
enable = 1;
TUNABLE_INT_FETCH("hw.nehemiah_rng_enable", &enable);
if (enable && (tmp = random_adaptor_get("nehemiah")))
*adaptor = tmp;
enable = 1;
TUNABLE_INT_FETCH("hw.ivy_rng_enable", &enable);
if (enable && (tmp = random_adaptor_get("rdrand")))
*adaptor = tmp;
}
/*
* Walk a list of registered random(4) adaptors and pick the last non-selected
* one.
*
* If none are selected, use yarrow if available.
*/
void
random_adaptor_choose(struct random_adaptor **adaptor)
{
char rngs[128], *token, *cp;
struct random_adaptors *rpp;
KASSERT(adaptor != NULL, ("pre-conditions failed"));
*adaptor = NULL;
random_adaptor_choose_legacy(adaptor);
if (*adaptor != NULL)
return;
if (TUNABLE_STR_FETCH("rngs_want", rngs, sizeof(rngs))) {
cp = rngs;
while ((token = strsep(&cp, ",")) != NULL) {
if ((*adaptor = random_adaptor_get(token)) != NULL)
break;
else if (bootverbose)
printf(
"%s random adaptor is not available, skipping\n",
token);
}
}
if (*adaptor == NULL) {
/*
* Either no RNGs are prefered via rngs_want tunable, or
* no prefered RNGs are registered.
* Fallback to Yarrow.
*/
*adaptor = random_adaptor_get("yarrow");
if (*adaptor == NULL) {
/*
* Yarrow doesn't seem to be available.
* Fallback to the first thing that's on the list of
* available RNGs.
*/
sx_slock(&adaptors_lock);
rpp = LIST_FIRST(&adaptors);
if (rpp != NULL)
*adaptor = rpp->rsp;
sx_sunlock(&adaptors_lock);
}
if (bootverbose && *adaptor)
printf("Falling back to <%s> random adaptor",
(*adaptor)->ident);
}
}
static void
random_adaptors_deinit(void *unused)
{
@ -99,18 +192,28 @@ static int
random_sysctl_adaptors_handler(SYSCTL_HANDLER_ARGS)
{
struct random_adaptors *rpp;
int error;
int error, count;
error = 0;
count = error = 0;
sx_slock(&adaptors_lock);
if (LIST_EMPTY(&adaptors))
error = SYSCTL_OUT(req, "", strlen(""));
if (LIST_EMPTY(&adaptors)) {
error = SYSCTL_OUT(req, "", 0);
} else {
LIST_FOREACH(rpp, &adaptors, entries) {
if (0 != SYSCTL_OUT(req, rpp->name, strlen(rpp->name)))
break;
LIST_FOREACH(rpp, &adaptors, entries) {
error = SYSCTL_OUT(req, ",", count++ ? 1 : 0);
if (error)
break;
error = SYSCTL_OUT(req, rpp->name, strlen(rpp->name));
if (error)
break;
}
}
sx_sunlock(&adaptors_lock);
@ -118,6 +221,37 @@ random_sysctl_adaptors_handler(SYSCTL_HANDLER_ARGS)
return (error);
}
static int
random_sysctl_active_adaptor_handler(SYSCTL_HANDLER_ARGS)
{
struct random_adaptor *rsp;
struct random_adaptors *rpp;
const char *name;
int error;
name = NULL;
rsp = random_get_active_adaptor();
if (rsp != NULL) {
sx_slock(&adaptors_lock);
LIST_FOREACH(rpp, &adaptors, entries) {
if (rpp->rsp == rsp)
name = rpp->name;
}
sx_sunlock(&adaptors_lock);
}
if (rsp == NULL || name == NULL) {
error = SYSCTL_OUT(req, "", 0);
} else {
error = SYSCTL_OUT(req, name, strlen(name));
}
return (error);
}
static void
random_adaptors_init(void *unused)
{
@ -127,6 +261,11 @@ random_adaptors_init(void *unused)
NULL, 0, random_sysctl_adaptors_handler, "",
"Random Number Generator adaptors");
SYSCTL_PROC(_kern_random, OID_AUTO, active_adaptor,
CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
NULL, 0, random_sysctl_active_adaptor_handler, "",
"Active Random Number Generator Adaptor");
sx_init(&adaptors_lock, "random_adaptors");
}

View File

@ -39,6 +39,7 @@ struct random_adaptors {
struct random_adaptor *random_adaptor_get(const char *);
int random_adaptor_register(const char *, struct random_adaptor *);
void random_adaptor_choose(struct random_adaptor **);
/*
* random_adaptor's should be registered prior to

View File

@ -0,0 +1,251 @@
/*-
* Copyright (c) 2013 Arthur Mesh
* Copyright (c) 2000-2009 Mark R V Murray
* Copyright (c) 2004 Robert N. M. Watson
* 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$
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/kthread.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/random.h>
#include <sys/sysctl.h>
#include <sys/unistd.h>
#include <dev/random/randomdev_soft.h>
#include "random_harvestq.h"
#define RANDOM_FIFO_MAX 256 /* How many events to queue up */
MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers");
/*
* The harvest mutex protects the consistency of the entropy fifos and
* empty fifo.
*/
struct mtx harvest_mtx;
/* Lockable FIFO queue holding entropy buffers */
struct entropyfifo {
int count;
STAILQ_HEAD(harvestlist, harvest) head;
};
/* Empty entropy buffers */
static struct entropyfifo emptyfifo;
#define EMPTYBUFFERS 1024
/* Harvested entropy */
static struct entropyfifo harvestfifo[ENTROPYSOURCE];
/* <0 to end the kthread, 0 to let it run, 1 to flush the harvest queues */
int random_kthread_control = 0;
static struct proc *random_kthread_proc;
static void
random_kthread(void *arg)
{
STAILQ_HEAD(, harvest) local_queue;
struct harvest *event = NULL;
int local_count;
enum esource source;
event_proc_f func = arg;
STAILQ_INIT(&local_queue);
local_count = 0;
/* Process until told to stop */
mtx_lock_spin(&harvest_mtx);
for (; random_kthread_control >= 0;) {
/* Cycle through all the entropy sources */
for (source = RANDOM_START; source < ENTROPYSOURCE; source++) {
/*
* Drain entropy source records into a thread-local
* queue for processing while not holding the mutex.
*/
STAILQ_CONCAT(&local_queue, &harvestfifo[source].head);
local_count += harvestfifo[source].count;
harvestfifo[source].count = 0;
}
/*
* Deal with events, if any, dropping the mutex as we process
* each event. Then push the events back into the empty
* fifo.
*/
if (!STAILQ_EMPTY(&local_queue)) {
mtx_unlock_spin(&harvest_mtx);
STAILQ_FOREACH(event, &local_queue, next)
func(event);
mtx_lock_spin(&harvest_mtx);
STAILQ_CONCAT(&emptyfifo.head, &local_queue);
emptyfifo.count += local_count;
local_count = 0;
}
KASSERT(local_count == 0, ("random_kthread: local_count %d",
local_count));
/*
* If a queue flush was commanded, it has now happened,
* and we can mark this by resetting the command.
*/
if (random_kthread_control == 1)
random_kthread_control = 0;
/* Work done, so don't belabour the issue */
msleep_spin_sbt(&random_kthread_control, &harvest_mtx,
"-", SBT_1S / 10, 0, C_PREL(1));
}
mtx_unlock_spin(&harvest_mtx);
random_set_wakeup_exit(&random_kthread_control);
/* NOTREACHED */
}
void
random_harvestq_init(event_proc_f cb)
{
int error, i;
struct harvest *np;
enum esource e;
/* Initialise the harvest fifos */
STAILQ_INIT(&emptyfifo.head);
emptyfifo.count = 0;
for (i = 0; i < EMPTYBUFFERS; i++) {
np = malloc(sizeof(struct harvest), M_ENTROPY, M_WAITOK);
STAILQ_INSERT_TAIL(&emptyfifo.head, np, next);
}
for (e = RANDOM_START; e < ENTROPYSOURCE; e++) {
STAILQ_INIT(&harvestfifo[e].head);
harvestfifo[e].count = 0;
}
mtx_init(&harvest_mtx, "entropy harvest mutex", NULL, MTX_SPIN);
/* Start the hash/reseed thread */
error = kproc_create(random_kthread, cb,
&random_kthread_proc, RFHIGHPID, 0, "rand_harvestq"); /* RANDOM_CSPRNG_NAME */
if (error != 0)
panic("Cannot create entropy maintenance thread.");
}
void
random_harvestq_deinit(void)
{
struct harvest *np;
enum esource e;
/* Destroy the harvest fifos */
while (!STAILQ_EMPTY(&emptyfifo.head)) {
np = STAILQ_FIRST(&emptyfifo.head);
STAILQ_REMOVE_HEAD(&emptyfifo.head, next);
free(np, M_ENTROPY);
}
for (e = RANDOM_START; e < ENTROPYSOURCE; e++) {
while (!STAILQ_EMPTY(&harvestfifo[e].head)) {
np = STAILQ_FIRST(&harvestfifo[e].head);
STAILQ_REMOVE_HEAD(&harvestfifo[e].head, next);
free(np, M_ENTROPY);
}
}
mtx_destroy(&harvest_mtx);
}
/*
* Entropy harvesting routine. This is supposed to be fast; do
* not do anything slow in here!
*/
void
random_harvestq_internal(u_int64_t somecounter, const void *entropy,
u_int count, u_int bits, u_int frac, enum esource origin)
{
struct harvest *event;
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. */
if (harvestfifo[origin].count >= RANDOM_FIFO_MAX)
return;
mtx_lock_spin(&harvest_mtx);
/*
* Don't make the harvest queues too big - help to prevent low-grade
* entropy swamping
*/
if (harvestfifo[origin].count < RANDOM_FIFO_MAX) {
event = STAILQ_FIRST(&emptyfifo.head);
if (event != NULL) {
/* Add the harvested data to the fifo */
STAILQ_REMOVE_HEAD(&emptyfifo.head, next);
harvestfifo[origin].count++;
event->somecounter = somecounter;
event->size = count;
event->bits = bits;
event->frac = frac;
event->source = origin;
/* XXXX Come back and make this dynamic! */
count = MIN(count, HARVESTSIZE);
memcpy(event->entropy, entropy, count);
#if 0
{
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);
}
}
mtx_unlock_spin(&harvest_mtx);
}

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2004 Mark R V Murray
* Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -23,40 +23,19 @@
* (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$
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#ifndef __RANDOM_HARVEST_H__
#define __RANDOM_HARVEST_H__
#if defined(__amd64__) || defined(__i386__)
#include "opt_cpu.h"
#endif
typedef void (*event_proc_f)(struct harvest *event);
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/selinfo.h>
void random_harvestq_init(event_proc_f);
void random_harvestq_deinit(void);
void random_harvestq_internal(u_int64_t, const void *,
u_int, u_int, u_int, enum esource);
#include <dev/random/random_adaptors.h>
#include <dev/random/randomdev.h>
extern int random_kthread_control;
void
random_ident_hardware(struct random_adaptor **adaptor)
{
struct random_adaptor *tmp;
int enable;
/* Set default to software (yarrow) */
*adaptor = random_adaptor_get("yarrow");
/* Then go looking for hardware */
enable = 1;
TUNABLE_INT_FETCH("hw.nehemiah_rng_enable", &enable);
if (enable && (tmp = random_adaptor_get("nehemiah")))
*adaptor = tmp;
enable = 1;
TUNABLE_INT_FETCH("hw.ivy_rng_enable", &enable);
if (enable && (tmp = random_adaptor_get("rdrand")))
*adaptor = tmp;
}
#endif /* __RANDOM_HARVEST_H__ */

View File

@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <machine/cpu.h>
#include <dev/random/random_adaptors.h>
#include <dev/random/randomdev.h>
#define RANDOM_MINOR 0
@ -85,6 +86,13 @@ random_null_func(void)
{
}
struct random_adaptor *
random_get_active_adaptor(void)
{
return (random_adaptor);
}
/* ARGSUSED */
static int
random_close(struct cdev *dev __unused, int flags, int fmt __unused,
@ -215,7 +223,7 @@ random_modevent(module_t mod __unused, int type, void *data __unused)
switch (type) {
case MOD_LOAD:
random_ident_hardware(&random_adaptor);
random_adaptor_choose(&random_adaptor);
if (random_adaptor == NULL) {
printf(

View File

@ -53,3 +53,4 @@ struct random_adaptor {
extern void random_ident_hardware(struct random_adaptor **);
extern void random_null_func(void);
struct random_adaptor *random_get_active_adaptor(void);

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,22 +26,24 @@
*
*/
#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$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/fcntl.h>
#include <sys/kernel.h>
#include <sys/kthread.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/poll.h>
#include <sys/proc.h>
#include <sys/random.h>
#include <sys/selinfo.h>
#include <sys/sysctl.h>
@ -54,55 +56,51 @@ __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 */
#include "random_harvestq.h"
static void random_kthread(void *);
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");
/*
* The harvest mutex protects the consistency of the entropy fifos and
* empty fifo.
*/
struct mtx harvest_mtx;
/* Lockable FIFO queue holding entropy buffers */
struct entropyfifo {
int count;
STAILQ_HEAD(harvestlist, harvest) head;
#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"
/* Empty entropy buffers */
static struct entropyfifo emptyfifo;
#define EMPTYBUFFERS 1024
/* Harvested entropy */
static struct entropyfifo harvestfifo[ENTROPYSOURCE];
/* <0 to end the kthread, 0 to let it run, 1 to flush the harvest queues */
static int random_kthread_control = 0;
static struct proc *random_kthread_proc;
#endif
/* List for the dynamic sysctls */
static struct sysctl_ctx_list random_clist;
@ -116,16 +114,17 @@ 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 +134,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,7 +155,7 @@ 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),
@ -164,40 +163,18 @@ random_yarrow_init(void)
&harvest.swi, 0, random_check_boolean, "I",
"Harvest SWI entropy");
/* Initialise the harvest fifos */
STAILQ_INIT(&emptyfifo.head);
emptyfifo.count = 0;
for (i = 0; i < EMPTYBUFFERS; i++) {
np = malloc(sizeof(struct harvest), M_ENTROPY, M_WAITOK);
STAILQ_INSERT_TAIL(&emptyfifo.head, np, next);
}
for (e = RANDOM_START; e < ENTROPYSOURCE; e++) {
STAILQ_INIT(&harvestfifo[e].head);
harvestfifo[e].count = 0;
}
mtx_init(&harvest_mtx, "entropy harvest mutex", NULL, MTX_SPIN);
/* Start the hash/reseed thread */
error = kproc_create(random_kthread, NULL,
&random_kthread_proc, RFHIGHPID, 0, "yarrow");
if (error != 0)
panic("Cannot create entropy maintenance thread.");
random_harvestq_init(random_process_event);
/* Register the randomness harvesting routine */
random_yarrow_init_harvester(random_harvest_internal,
random_yarrow_read);
randomdev_init_harvester(random_harvestq_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
@ -205,140 +182,18 @@ random_yarrow_deinit(void)
random_kthread_control = -1;
tsleep((void *)&random_kthread_control, 0, "term", 0);
/* Destroy the harvest fifos */
while (!STAILQ_EMPTY(&emptyfifo.head)) {
np = STAILQ_FIRST(&emptyfifo.head);
STAILQ_REMOVE_HEAD(&emptyfifo.head, next);
free(np, M_ENTROPY);
}
for (e = RANDOM_START; e < ENTROPYSOURCE; e++) {
while (!STAILQ_EMPTY(&harvestfifo[e].head)) {
np = STAILQ_FIRST(&harvestfifo[e].head);
STAILQ_REMOVE_HEAD(&harvestfifo[e].head, next);
free(np, M_ENTROPY);
}
}
#if defined(YARROW_RNG)
random_yarrow_deinit_alg();
mtx_destroy(&harvest_mtx);
#endif
#if defined(FORTUNA_RNG)
random_fortuna_deinit_alg();
#endif
sysctl_ctx_free(&random_clist);
}
/* ARGSUSED */
static void
random_kthread(void *arg __unused)
{
STAILQ_HEAD(, harvest) local_queue;
struct harvest *event = NULL;
int local_count;
enum esource source;
STAILQ_INIT(&local_queue);
local_count = 0;
/* Process until told to stop */
mtx_lock_spin(&harvest_mtx);
for (; random_kthread_control >= 0;) {
/* Cycle through all the entropy sources */
for (source = RANDOM_START; source < ENTROPYSOURCE; source++) {
/*
* Drain entropy source records into a thread-local
* queue for processing while not holding the mutex.
*/
STAILQ_CONCAT(&local_queue, &harvestfifo[source].head);
local_count += harvestfifo[source].count;
harvestfifo[source].count = 0;
}
/*
* Deal with events, if any, dropping the mutex as we process
* each event. Then push the events back into the empty
* fifo.
*/
if (!STAILQ_EMPTY(&local_queue)) {
mtx_unlock_spin(&harvest_mtx);
STAILQ_FOREACH(event, &local_queue, next)
random_process_event(event);
mtx_lock_spin(&harvest_mtx);
STAILQ_CONCAT(&emptyfifo.head, &local_queue);
emptyfifo.count += local_count;
local_count = 0;
}
KASSERT(local_count == 0, ("random_kthread: local_count %d",
local_count));
/*
* If a queue flush was commanded, it has now happened,
* and we can mark this by resetting the command.
*/
if (random_kthread_control == 1)
random_kthread_control = 0;
/* Work done, so don't belabour the issue */
msleep_spin_sbt(&random_kthread_control, &harvest_mtx,
"-", SBT_1S / 10, 0, C_PREL(1));
}
mtx_unlock_spin(&harvest_mtx);
random_set_wakeup_exit(&random_kthread_control);
/* NOTREACHED */
}
/* Entropy harvesting routine. This is supposed to be fast; do
* not do anything slow in here!
*/
static void
random_harvest_internal(u_int64_t somecounter, const void *entropy,
u_int count, u_int bits, u_int frac, enum esource origin)
{
struct harvest *event;
KASSERT(origin == RANDOM_START || origin == RANDOM_WRITE ||
origin == RANDOM_KEYBOARD || origin == RANDOM_MOUSE ||
origin == RANDOM_NET || origin == RANDOM_INTERRUPT ||
origin == RANDOM_PURE,
("random_harvest_internal: origin %d invalid\n", origin));
/* Lockless read to avoid lock operations if fifo is full. */
if (harvestfifo[origin].count >= RANDOM_FIFO_MAX)
return;
mtx_lock_spin(&harvest_mtx);
/*
* Don't make the harvest queues too big - help to prevent low-grade
* entropy swamping
*/
if (harvestfifo[origin].count < RANDOM_FIFO_MAX) {
event = STAILQ_FIRST(&emptyfifo.head);
if (event != NULL) {
/* Add the harvested data to the fifo */
STAILQ_REMOVE_HEAD(&emptyfifo.head, next);
harvestfifo[origin].count++;
event->somecounter = somecounter;
event->size = count;
event->bits = bits;
event->frac = frac;
event->source = origin;
/* XXXX Come back and make this dynamic! */
count = MIN(count, HARVESTSIZE);
memcpy(event->entropy, entropy, count);
STAILQ_INSERT_TAIL(&harvestfifo[origin].head,
event, next);
}
}
mtx_unlock_spin(&harvest_mtx);
}
void
random_yarrow_write(void *buf, int count)
randomdev_write(void *buf, int count)
{
int i;
u_int chunk;
@ -351,52 +206,52 @@ random_yarrow_write(void *buf, int count)
chunk = HARVESTSIZE;
if (i + chunk >= count)
chunk = (u_int)(count - i);
random_harvest_internal(get_cyclecount(), (char *)buf + i,
random_harvestq_internal(get_cyclecount(), (char *)buf + i,
chunk, 0, 0, RANDOM_WRITE);
}
}
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 +263,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 +297,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);

View File

@ -152,7 +152,7 @@ rndtest_harvest(struct rndtest_state *rsp, void *buf, u_int len)
for (len /= sizeof (u_int32_t); len; len--)
add_true_randomness(*p++);
#else
random_harvest(buf, len, len*NBBY, 0, RANDOM_PURE);
random_harvest(buf, len, len*NBBY/2, 0, RANDOM_PURE);
#endif
}
}

View File

@ -211,7 +211,7 @@ safe_partname(struct safe_softc *sc)
static void
default_harvest(struct rndtest_state *rsp, void *buf, u_int count)
{
random_harvest(buf, count, count*NBBY, 0, RANDOM_PURE);
random_harvest(buf, count, count*NBBY/2, 0, RANDOM_PURE);
}
#endif /* SAFE_NO_RNG */

View File

@ -259,7 +259,7 @@ ubsec_partname(struct ubsec_softc *sc)
static void
default_harvest(struct rndtest_state *rsp, void *buf, u_int count)
{
random_harvest(buf, count, count*NBBY, 0, RANDOM_PURE);
random_harvest(buf, count, count*NBBY/2, 0, RANDOM_PURE);
}
static int

View File

@ -1147,7 +1147,7 @@ swi_sched(void *cookie, int flags)
entropy.event = (uintptr_t)ih;
entropy.td = curthread;
random_harvest(&entropy, sizeof(entropy), 1, 0,
RANDOM_INTERRUPT);
RANDOM_SWI);
}
/*

View File

@ -131,7 +131,7 @@ octeon_rnd_harvest(void *arg)
for (i = 0; i < OCTEON_RND_WORDS; i++)
sc->sc_entropy[i] = cvmx_rng_get_random64();
random_harvest(sc->sc_entropy, sizeof sc->sc_entropy,
sizeof sc->sc_entropy * 8, 0, RANDOM_PURE);
(sizeof(sc->sc_entropy)*8)/2, 0, RANDOM_PURE);
callout_reset(&sc->sc_callout, hz * 5, octeon_rnd_harvest, sc);
}

View File

@ -5,7 +5,7 @@
.PATH: ${.CURDIR}/../../crypto/sha2
KMOD= random
SRCS= randomdev.c probe.c
SRCS= randomdev.c
.if ${MACHINE} == "amd64" || ${MACHINE} == "i386"
SRCS+= nehemiah.c
SRCS+= ivy.c

View File

@ -638,9 +638,8 @@ ether_input_internal(struct ifnet *ifp, struct mbuf *m)
m->m_flags |= M_PROMISC;
}
/* First chunk of an mbuf contains good entropy */
if (harvest.ethernet)
random_harvest(m, 16, 3, 0, RANDOM_NET);
random_harvest(&(m->m_data), 12, 3, 0, RANDOM_NET_ETHER);
ether_demux(ifp, m);
CURVNET_RESTORE();

View File

@ -920,9 +920,8 @@ tunwrite(struct cdev *dev, struct uio *uio, int flag)
m_freem(m);
return (EAFNOSUPPORT);
}
/* First chunk of an mbuf contains good junk */
if (harvest.point_to_point)
random_harvest(m, 16, 3, 0, RANDOM_NET);
random_harvest(&(m->m_data), 12, 3, 0, RANDOM_NET_TUN);
ifp->if_ibytes += m->m_pkthdr.len;
ifp->if_ipackets++;
CURVNET_SET(ifp->if_vnet);

View File

@ -774,9 +774,8 @@ ng_iface_rcvdata(hook_p hook, item_p item)
m_freem(m);
return (EAFNOSUPPORT);
}
/* First chunk of an mbuf contains good junk */
if (harvest.point_to_point)
random_harvest(m, 16, 3, 0, RANDOM_NET);
random_harvest(&(m->m_data), 12, 3, 0, RANDOM_NET_NG);
M_SETFIB(m, ifp->if_fib);
netisr_dispatch(isr, m);
return (0);

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2000 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
@ -42,8 +42,11 @@ enum esource {
RANDOM_WRITE = 0,
RANDOM_KEYBOARD,
RANDOM_MOUSE,
RANDOM_NET,
RANDOM_NET_TUN,
RANDOM_NET_ETHER,
RANDOM_NET_NG,
RANDOM_INTERRUPT,
RANDOM_SWI,
RANDOM_PURE,
ENTROPYSOURCE
};
@ -57,6 +60,7 @@ struct harvest_select {
int point_to_point;
int interrupt;
int swi;
int namei;
};
extern struct harvest_select harvest;