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:
commit
42ac52f951
@ -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>
|
||||
|
6
share/examples/kld/random_adaptor/Makefile
Normal file
6
share/examples/kld/random_adaptor/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
# $FreeBSD$
|
||||
|
||||
KMOD= random_adaptor_example
|
||||
SRCS= ${KMOD}.c
|
||||
|
||||
.include <bsd.kmod.mk>
|
94
share/examples/kld/random_adaptor/random_adaptor_example.c
Normal file
94
share/examples/kld/random_adaptor/random_adaptor_example.c
Normal 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);
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
119
sys/dev/random/pseudo_rng.c
Normal file
119
sys/dev/random/pseudo_rng.c
Normal 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);
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
251
sys/dev/random/random_harvestq.c
Normal file
251
sys/dev/random/random_harvestq.c
Normal 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);
|
||||
}
|
||||
|
@ -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__ */
|
@ -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(
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user