Add DEV_RANDOM pseudo-option and use it to "include out" random(4)

if desired.

Retire randomdev_none.c and introduce random_infra.c for resident
infrastructure. Completely stub out random(4) calls in the "without
DEV_RANDOM" case.

Add RANDOM_LOADABLE option to allow loadable Yarrow/Fortuna/LocallyWritten
algorithm.  Add a skeleton "other" algorithm framework for folks
to add their own processing code. NIST, anyone?

Retire the RANDOM_DUMMY option.

Build modules for Yarrow, Fortuna and "other".

Use atomics for the live entropy rate-tracking.

Convert ints to bools for the 'seeded' logic.

Move _write() function from the algorithm-specific areas to randomdev.c

Get rid of reseed() function - it is unused.

Tidy up the opt_*.h includes.

Update documentation for random(4) modules.

Fix test program (reviewers, please leave this).

Differential Revision:    https://reviews.freebsd.org/D3354
Reviewed by:              wblock,delphij,jmg,bjk
Approved by:              so (/dev/random blanket)
This commit is contained in:
Mark Murray 2015-08-17 07:36:12 +00:00
parent 7a40703db9
commit 646041a89a
21 changed files with 719 additions and 363 deletions

View File

@ -31,6 +31,21 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 11.x IS SLOW:
disable the most expensive debugging functionality run
"ln -s 'abort:false,junk:false' /etc/malloc.conf".)
20150817:
Kernel-loadable modules for the random(4) device are back. To use
them, the kernel must have
device random
options RANDOM_LOADABLE
kldload(8) can then be used to load random_fortuna.ko
or random_yarrow.ko. Please note that due to the indirect
function calls that the loadable modules need to provide,
the build-in variants will be slightly more efficient.
The random(4) kernel option RANDOM_DUMMY has been retired due to
unpopularity. It was not all that useful anyway.
20150813:
The WITHOUT_ELFTOOLCHAIN_TOOLS src.conf(5) knob has been retired.
Control over building the ELF Tool Chain tools is now provided by

View File

@ -23,7 +23,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd June 30, 2015
.Dd August 17, 2015
.Dt RANDOM 4
.Os
.Sh NAME
@ -31,6 +31,7 @@
.Nd the entropy device
.Sh SYNOPSIS
.Cd "device random"
.Cd "options RANDOM_LOADABLE"
.Sh DESCRIPTION
The
.Nm
@ -133,15 +134,49 @@ The
.Va kern.random.harvest.mask_bin
and
.Va kern.random.harvest.mask_symbolic
sysctl
can be used confirm
that your choices are correct.
sysctls
can be used to confirm
that the choices are correct.
Note that disabled items
in the latter item
are listed in square brackets.
See
.Xr random_harvest 9
for more on the harvesting of entropy.
.Pp
When
.Cd "options RANDOM_LOADABLE"
is used,
the
.Pa /dev/random
device is not created
until an "algorithm module"
is loaded.
Two of these modules
are built by default,
.Em random_fortuna
and
.Em random_yarrow .
The
.Em random_yarrow
module is deprecated,
and will be removed in
.Fx 12.
Use of the Yarrow algorithm
is not encouraged,
but while still present
in the kernel source,
it can be selected with the
.Cd "options RANDOM_YARROW"
kernel option.
Note that these loadable modules
are slightly less efficient
than their compiled-in equivalents.
This is because some functions
must be locked against
load and unload events,
and also must be indirect calls
to allow for removal.
.Sh RANDOMNESS
The use of randomness in the field of computing
is a rather subtle issue because randomness means
@ -294,7 +329,7 @@ It replaces the previous
implementation,
introduced in
.Fx 5.0 .
The older
.Em Yarrow
algorithm remains available
as a compile-time fallback.
The Yarrow algorithm
is no longer supported
by its authors,
and is therefore deprecated.

View File

@ -2981,9 +2981,10 @@ options MAXFILES=999
# Random number generator
# Only ONE of the below two may be used; they are mutually exclusive.
# If neither is present, then the Fortuna algorithm is used.
options RANDOM_YARROW # Yarrow CSPRNG (old default)
#options RANDOM_DUMMY # Dummy CSPRNG that always blocks
# If neither is present, then the Fortuna algorithm is selected.
#options RANDOM_YARROW # Yarrow CSPRNG (old default)
#options RANDOM_LOADABLE # Allow the algorithm to be loaded as
# a module.
# For developers.
options RANDOM_DEBUG # Extra debugging messages

View File

@ -550,14 +550,14 @@ crypto/des/des_ecb.c optional crypto | ipsec | netsmb
crypto/des/des_setkey.c optional crypto | ipsec | netsmb
crypto/rc4/rc4.c optional netgraph_mppc_encryption | kgssapi
crypto/rijndael/rijndael-alg-fst.c optional crypto | geom_bde | \
ipsec | random random_yarrow | random !random_yarrow !random_dummy | wlan_ccmp
crypto/rijndael/rijndael-api-fst.c optional geom_bde | random random_yarrow | random !random_yarrow !random_dummy
ipsec | random !random_loadable | wlan_ccmp
crypto/rijndael/rijndael-api-fst.c optional geom_bde | random !random_loadable
crypto/rijndael/rijndael-api.c optional crypto | ipsec | wlan_ccmp
crypto/sha1.c optional carp | crypto | ipsec | \
netgraph_mppc_encryption | sctp
crypto/sha2/sha2.c optional crypto | geom_bde | ipsec | random random_yarrow | random !random_yarrow !random_dummy | \
crypto/sha2/sha2.c optional crypto | geom_bde | ipsec | random !random_loadable | \
sctp | zfs
crypto/sha2/sha256c.c optional crypto | geom_bde | ipsec | random random_yarrow | random !random_yarrow !random_dummy | \
crypto/sha2/sha256c.c optional crypto | geom_bde | ipsec | random !random_loadable | \
sctp | zfs
crypto/siphash/siphash.c optional inet | inet6
crypto/siphash/siphash_test.c optional inet | inet6
@ -2314,12 +2314,14 @@ rt2860.fw optional rt2860fw | ralfw \
compile-with "${NORMAL_FW}" \
no-obj no-implicit-rule \
clean "rt2860.fw"
dev/random/randomdev_none.c optional !random
dev/random/randomdev.c optional random
dev/random/random_harvestq.c optional random random_yarrow | random !random_dummy
dev/random/random_infra.c optional random
dev/random/random_harvestq.c optional random
dev/random/randomdev.c optional random random_yarrow | \
random !random_yarrow !random_loadable
dev/random/yarrow.c optional random random_yarrow
dev/random/fortuna.c optional random !random_yarrow !random_dummy
dev/random/hash.c optional random random_yarrow | random !random_dummy
dev/random/fortuna.c optional random !random_yarrow !random_loadable
dev/random/hash.c optional random random_yarrow | \
random !random_yarrow !random_loadable
dev/rc/rc.c optional rc
dev/re/if_re.c optional re
dev/rl/if_rl.c optional rl pci

View File

@ -711,6 +711,7 @@ DEV_PCI opt_pci.h
DEV_PF opt_pf.h
DEV_PFLOG opt_pf.h
DEV_PFSYNC opt_pf.h
DEV_RANDOM opt_global.h
DEV_SPLASH opt_splash.h
DEV_VLAN opt_vlan.h
@ -946,13 +947,14 @@ RCTL opt_global.h
# The DEBUG option is in global.h as the random harvesting
# puts probes all over the place, and it makes little sense
# to pollute these headers with an extra include.
# the DUMMY option is in global.h because it is used to
# turn off harvesting all over the kernel.
RANDOM_DEBUG opt_global.h
RANDOM_DEBUG opt_random.h
# Which CSPRNG hashes we get.
# These are mutually exclusive. With neither, Fortuna is selected.
RANDOM_DUMMY opt_global.h
# If Yarrow is not chosen, Fortuna is selected.
RANDOM_YARROW opt_random.h
# With this, no entropy processor is loaded, but the entropy
# harvesting infrastructure is present. This means an entropy
# processor may be loaded as a module.
RANDOM_LOADABLE opt_random.h
# Intel em(4) driver
EM_MULTIQUEUE opt_em.h

View File

@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$");
#include <dev/random/fortuna.h>
#else /* !_KERNEL */
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -124,9 +125,7 @@ static uint8_t zero_region[RANDOM_ZERO_BLOCKSIZE];
static void random_fortuna_pre_read(void);
static void random_fortuna_read(uint8_t *, u_int);
static void random_fortuna_write(uint8_t *, u_int);
static void random_fortuna_reseed(void);
static int random_fortuna_seeded(void);
static bool random_fortuna_seeded(void);
static void random_fortuna_process_event(struct harvest_event *);
static void random_fortuna_init_alg(void *);
static void random_fortuna_deinit_alg(void *);
@ -139,8 +138,6 @@ struct random_algorithm random_alg_context = {
.ra_deinit_alg = random_fortuna_deinit_alg,
.ra_pre_read = random_fortuna_pre_read,
.ra_read = random_fortuna_read,
.ra_write = random_fortuna_write,
.ra_reseed = random_fortuna_reseed,
.ra_seeded = random_fortuna_seeded,
.ra_event_processor = random_fortuna_process_event,
.ra_poolcount = RANDOM_FORTUNA_NPOOLS,
@ -420,43 +417,7 @@ random_fortuna_read(uint8_t *buf, u_int bytecount)
RANDOM_RESEED_UNLOCK();
}
/* Internal function to hand external entropy to the PRNG. */
void
random_fortuna_write(uint8_t *buf, u_int count)
{
static u_int destination = 0;
struct harvest_event event;
struct randomdev_hash hash;
uint32_t entropy_data[RANDOM_KEYSIZE_WORDS], timestamp;
int i;
/* Extra timing here is helpful to scrape scheduler timing entropy */
randomdev_hash_init(&hash);
timestamp = (uint32_t)get_cyclecount();
randomdev_hash_iterate(&hash, &timestamp, sizeof(timestamp));
randomdev_hash_iterate(&hash, buf, count);
timestamp = (uint32_t)get_cyclecount();
randomdev_hash_iterate(&hash, &timestamp, sizeof(timestamp));
randomdev_hash_finish(&hash, entropy_data);
explicit_bzero(&hash, sizeof(hash));
for (i = 0; i < RANDOM_KEYSIZE_WORDS; i += sizeof(event.he_entropy)/sizeof(event.he_entropy[0])) {
event.he_somecounter = (uint32_t)get_cyclecount();
event.he_size = sizeof(event.he_entropy);
event.he_bits = event.he_size/8;
event.he_source = RANDOM_CACHED;
event.he_destination = destination++; /* Harmless cheating */
memcpy(event.he_entropy, entropy_data + i, sizeof(event.he_entropy));
random_fortuna_process_event(&event);
}
explicit_bzero(entropy_data, sizeof(entropy_data));
}
void
random_fortuna_reseed(void)
{
}
int
bool
random_fortuna_seeded(void)
{

View File

@ -0,0 +1,209 @@
/*-
* Copyright (c) 2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/*-
* This is a skeleton for folks who wish to build a loadable module
* containing an alternative entropy-processing algorithm for random(4).
*
* The functions below should be completed with the appropriate code,
* and the nearby yarrow.c and fortuna.c may be consulted for examples
* of working code.
*
* The author is willing to provide reasonable help to those wishing to
* write such a module for themselves. Please use the markm@ FreeBSD
* email address, and ensure that you are developing this on a suitably
* supported branch (This is currently 11-CURRENT, and will be no
* older than 11-STABLE in the future).
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/random.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
#include <machine/cpu.h>
#include <crypto/rijndael/rijndael-api-fst.h>
#include <crypto/sha2/sha2.h>
#include <dev/random/hash.h>
#include <dev/random/randomdev.h>
#include <dev/random/random_harvestq.h>
#include <dev/random/uint128.h>
#include <dev/random/other_algorithm.h>
static void random_other_pre_read(void);
static void random_other_read(uint8_t *, u_int);
static bool random_other_seeded(void);
static void random_other_process_event(struct harvest_event *);
static void random_other_init_alg(void *);
static void random_other_deinit_alg(void *);
/*
* RANDOM_OTHER_NPOOLS is used when reading hardware random
* number sources to ensure that each pool gets one read sample
* per loop iteration. Yarrow has 2 such pools (FAST and SLOW),
* and fortuna has 32 (0-31). The RNG used prior to Yarrow and
* ported from Linux had just 1 pool.
*/
#define RANDOM_OTHER_NPOOLS 1
struct random_algorithm random_alg_context = {
.ra_ident = "other",
.ra_init_alg = random_other_init_alg,
.ra_deinit_alg = random_other_deinit_alg,
.ra_pre_read = random_other_pre_read,
.ra_read = random_other_read,
.ra_seeded = random_other_seeded,
.ra_event_processor = random_other_process_event,
.ra_poolcount = RANDOM_OTHER_NPOOLS,
};
/* Use a mutex to protect your reseed variables? */
static mtx_t other_mtx;
/*
* void random_other_init_alg(void *unused __unused)
*
* Do algorithm-specific initialisation here.
*/
void
random_other_init_alg(void *unused __unused)
{
RANDOM_RESEED_INIT_LOCK();
/*
* Do set-up work here!
*/
}
/*
* void random_other_deinit_alg(void *unused __unused)
*
* Do algorithm-specific deinitialisation here.
*/
static void
random_other_deinit_alg(void *unused __unused)
{
/*
* Do tear-down work here!
*/
RANDOM_RESEED_DEINIT_LOCK();
}
/*
* void random_other_pre_read(void)
*
* Do any pre-read preparation you need to. This will be called
* before >=1 calls to random_other_read() corresponding to one
* read(2).
*
* This routine will be called periodically while the generator is
* still blocked and a read is being attempted, giving you an
* opportunity to unblock.
*/
static void
random_other_pre_read(void)
{
RANDOM_RESEED_LOCK();
/*
* Do pre-read housekeeping work here!
* You may use this as a chance to unblock the generator.
*/
RANDOM_RESEED_UNLOCK();
}
/*
* void random_other_read(uint8_t *buf, u_int count)
*
* Generate <count> bytes of output into <*buf>.
* You may use the fact that <count> will be a multiple of
* RANDOM_BLOCKSIZE for optimization purposes.
*
* This function will always be called with your generator
* unblocked and ready. If you are not ready to generate
* output here, then feel free to KASSERT() or panic().
*/
static void
random_other_read(uint8_t *buf, u_int count)
{
RANDOM_RESEED_LOCK();
/*
* Do random-number generation work here!
*/
RANDOM_RESEED_UNLOCK();
}
/*
* bool random_other_seeded(void)
*
* Return true if your generator is ready to generate
* output, and false otherwise.
*/
static bool
random_other_seeded(void)
{
bool seeded = false;
/*
* Find out if your generator is seeded here!
*/
return (seeded);
}
/*
* void random_other_process_event(struct harvest_event *event)
*
* Process one stochastic event <*event> into your entropy
* processor.
*
* The structure of the event may change, so it is easier to
* just grab the whole thing into your accumulation system.
* You may pick-and-choose bits, but please don't complain
* when/if these change.
*/
static void
random_other_process_event(struct harvest_event *event)
{
RANDOM_RESEED_LOCK();
/*
* Do entropy accumulation work here!
* You may use this as a chance to unblock the generator.
*/
RANDOM_RESEED_UNLOCK();
}

View File

@ -0,0 +1,62 @@
/*-
* Copyright (c) 2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/*-
* This is a skeleton for folks who wish to build a loadable module
* containing an alternative entropy-processing algorithm for random(4).
*
* The functions below should be completed with the appropriate code,
* and the nearby yarrow.c and fortuna.c may be consulted for examples
* of working code.
*
* The author is willing to provide reasonable help to those wishing to
* write such a module for themselves. Please use the markm@ FreeBSD
* email address, and ensure that you are developing this on a suitably
* supported branch (This is currently 11-CURRENT, and will be no
* older than 11-STABLE in the future).
*/
#ifndef SYS_DEV_RANDOM_OTHER_H_INCLUDED
#define SYS_DEV_RANDOM_OTHER_H_INCLUDED
#ifdef _KERNEL
typedef struct mtx mtx_t;
#define RANDOM_RESEED_INIT_LOCK(x) mtx_init(&other_mtx, "reseed mutex", NULL, MTX_DEF)
#define RANDOM_RESEED_DEINIT_LOCK(x) mtx_destroy(&other_mtx)
#define RANDOM_RESEED_LOCK(x) mtx_lock(&other_mtx)
#define RANDOM_RESEED_UNLOCK(x) mtx_unlock(&other_mtx)
#define RANDOM_RESEED_ASSERT_LOCK_OWNED(x) mtx_assert(&other_mtx, MA_OWNED)
#else
#define RANDOM_RESEED_INIT_LOCK(x) mtx_init(&other_mtx, mtx_plain)
#define RANDOM_RESEED_DEINIT_LOCK(x) mtx_destroy(&other_mtx)
#define RANDOM_RESEED_LOCK(x) mtx_lock(&other_mtx)
#define RANDOM_RESEED_UNLOCK(x) mtx_unlock(&other_mtx)
#define RANDOM_RESEED_ASSERT_LOCK_OWNED(x)
#endif
#endif /* SYS_DEV_RANDOM_OTHER_H_INCLUDED */

View File

@ -47,12 +47,21 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#include <sys/unistd.h>
#if defined(RANDOM_LOADABLE)
#include <sys/lock.h>
#include <sys/sx.h>
#endif
#include <machine/atomic.h>
#include <machine/cpu.h>
#include <dev/random/randomdev.h>
#include <dev/random/random_harvestq.h>
static void random_kthread(void);
static void random_sources_feed(void);
static u_int read_rate;
/* List for the dynamic sysctls */
static struct sysctl_ctx_list random_clist;
@ -66,7 +75,7 @@ static struct sysctl_ctx_list random_clist;
#define RANDOM_RING_MAX 1024
#define RANDOM_ACCUM_MAX 8
/* 1 to let the kernel thread run, 0 to terminate */
/* 1 to let the kernel thread run, 0 to terminate, -1 to mark completion */
volatile int random_kthread_control;
/*
@ -123,13 +132,18 @@ static struct kproc_desc random_proc_kp = {
&harvest_context.hc_kthread_proc,
};
/* Pass the given event straight through to Fortuna/Yarrow/Whatever. */
static __inline void
random_harvestq_fast_process_event(struct harvest_event *event)
{
if (random_alg_context.ra_event_processor)
random_alg_context.ra_event_processor(event);
#if defined(RANDOM_LOADABLE)
RANDOM_CONFIG_S_LOCK();
if (p_random_alg_context)
#endif
p_random_alg_context->ra_event_processor(event);
#if defined(RANDOM_LOADABLE)
RANDOM_CONFIG_S_UNLOCK();
#endif
}
static void
@ -163,12 +177,58 @@ random_kthread(void)
/* XXX: FIX!! This is a *great* place to pass hardware/live entropy to random(9) */
tsleep_sbt(&harvest_context.hc_kthread_proc, 0, "-", SBT_1S/10, 0, C_PREL(1));
}
random_kthread_control = -1;
wakeup(&harvest_context.hc_kthread_proc);
kproc_exit(0);
/* NOTREACHED */
}
/* This happens well after SI_SUB_RANDOM */
SYSINIT(random_device_h_proc, SI_SUB_CREATE_INIT, SI_ORDER_ANY, kproc_start, &random_proc_kp);
/*
* Run through all fast sources reading entropy for the given
* number of rounds, which should be a multiple of the number
* of entropy accumulation pools in use; 2 for Yarrow and 32
* for Fortuna.
*/
static void
random_sources_feed(void)
{
uint32_t entropy[HARVESTSIZE];
struct random_sources *rrs;
u_int i, n, local_read_rate;
/*
* Step over all of live entropy sources, and feed their output
* to the system-wide RNG.
*/
#if defined(RANDOM_LOADABLE)
RANDOM_CONFIG_S_LOCK();
if (p_random_alg_context) {
/* It's an indenting error. Yeah, Yeah. */
#endif
local_read_rate = atomic_readandclear_32(&read_rate);
LIST_FOREACH(rrs, &source_list, rrs_entries) {
for (i = 0; i < p_random_alg_context->ra_poolcount*(local_read_rate + 1); i++) {
n = rrs->rrs_source->rs_read(entropy, sizeof(entropy));
KASSERT((n > 0 && n <= sizeof(entropy)), ("very bad return from rs_read (= %d) in %s", n, __func__));
random_harvest_direct(entropy, n, (n*8)/2, rrs->rrs_source->rs_source);
}
}
explicit_bzero(entropy, sizeof(entropy));
#if defined(RANDOM_LOADABLE)
}
RANDOM_CONFIG_S_UNLOCK();
#endif
}
void
read_rate_increment(u_int chunk)
{
atomic_add_32(&read_rate, chunk);
}
/* ARGSUSED */
RANDOM_CHECK_UINT(harvestmask, 0, RANDOM_HARVEST_EVERYTHING_MASK);
@ -317,7 +377,8 @@ random_harvestq_deinit(void *unused __unused)
/* Command the hash/reseed thread to end and wait for it to finish */
random_kthread_control = 0;
tsleep(&harvest_context.hc_kthread_proc, 0, "harvqterm", 0);
while (random_kthread_control >= 0)
tsleep(&harvest_context.hc_kthread_proc, 0, "harvqterm", hz/5);
sysctl_ctx_free(&random_clist);
}
SYSUNINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_SECOND, random_harvestq_deinit, NULL);
@ -412,3 +473,5 @@ random_harvest_direct(const void *entropy, u_int size, u_int bits, enum random_e
random_harvestq_fast_process_event(&event);
explicit_bzero(&event, sizeof(event));
}
MODULE_VERSION(random_harvestq, 1);

View File

@ -43,6 +43,8 @@ struct harvest_event {
uint8_t he_source; /* origin of the entropy */
} __packed;
void read_rate_increment(u_int);
#define RANDOM_HARVESTQ_BOOT_ENTROPY_FILE "/boot/entropy"
#define RANDOM_HARVEST_INIT_LOCK(x) mtx_init(&harvest_context.hc_mtx, "entropy harvest mutex", NULL, MTX_SPIN)

View File

@ -0,0 +1,128 @@
/*-
* Copyright (c) 2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/random.h>
#include <sys/sysctl.h>
#if defined(RANDOM_LOADABLE)
#include <sys/lock.h>
#include <sys/sx.h>
#endif
#include <dev/random/randomdev.h>
/* Set up the sysctl root node for the entropy device */
SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Cryptographically Secure Random Number Generator");
MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures");
struct sources_head source_list = LIST_HEAD_INITIALIZER(source_list);
#if defined(RANDOM_LOADABLE)
struct random_algorithm *p_random_alg_context = NULL;
#else /* !defined(RANDOM_LOADABLE) */
struct random_algorithm *p_random_alg_context = &random_alg_context;
#endif /* defined(RANDOM_LOADABLE) */
#if defined(RANDOM_LOADABLE)
struct random_readers {
int (*read_random_uio)(struct uio *, bool);
u_int (*read_random)(void *, u_int);
} random_reader_context = {
(int (*)(struct uio *, bool))nullop,
(u_int (*)(void *, u_int))nullop,
};
struct sx randomdev_config_lock;
static void
random_infra_sysinit(void *dummy __unused)
{
RANDOM_CONFIG_INIT_LOCK();
}
SYSINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_FIRST, random_infra_sysinit, NULL);
void
random_infra_init(int (*p_random_read_uio)(struct uio *, bool), u_int (*p_random_read)(void *, u_int))
{
RANDOM_CONFIG_X_LOCK();
random_reader_context.read_random_uio = p_random_read_uio;
random_reader_context.read_random = p_random_read;
RANDOM_CONFIG_X_UNLOCK();
}
void
random_infra_uninit(void)
{
RANDOM_CONFIG_X_LOCK();
random_reader_context.read_random_uio = (int (*)(struct uio *, bool))nullop;
random_reader_context.read_random = (u_int (*)(void *, u_int))nullop;
RANDOM_CONFIG_X_UNLOCK();
}
static void
random_infra_sysuninit(void *dummy __unused)
{
RANDOM_CONFIG_DEINIT_LOCK();
}
SYSUNINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_FIRST, random_infra_sysuninit, NULL);
int
read_random_uio(struct uio *uio, bool nonblock)
{
int retval;
RANDOM_CONFIG_S_LOCK();
retval = random_reader_context.read_random_uio(uio, nonblock);
RANDOM_CONFIG_S_UNLOCK();
return (retval);
}
u_int
read_random(void *buf, u_int len)
{
u_int retval;
RANDOM_CONFIG_S_LOCK();
retval = random_reader_context.read_random(buf, len);
RANDOM_CONFIG_S_UNLOCK();
return (retval);
}
#endif /* defined(RANDOM_LOADABLE) */

View File

@ -56,14 +56,18 @@ __FBSDID("$FreeBSD$");
#include <dev/random/randomdev.h>
#include <dev/random/random_harvestq.h>
#include "opt_random.h"
#if defined(RANDOM_DUMMY) && defined(RANDOM_YARROW)
#error "Cannot define both RANDOM_DUMMY and RANDOM_YARROW"
#endif
#define RANDOM_UNIT 0
#if defined(RANDOM_LOADABLE)
#define READ_RANDOM_UIO _read_random_uio
#define READ_RANDOM _read_random
static int READ_RANDOM_UIO(struct uio *, bool);
static u_int READ_RANDOM(void *, u_int);
#else
#define READ_RANDOM_UIO read_random_uio
#define READ_RANDOM read_random
#endif
/* Return the largest number >= x that is a multiple of m */
#define CEIL_TO_MULTIPLE(x, m) ((((x) + (m) - 1)/(m))*(m))
@ -84,68 +88,31 @@ static struct cdevsw random_cdevsw = {
/* For use with make_dev(9)/destroy_dev(9). */
static struct cdev *random_dev;
/* Set up the sysctl root node for the entropy device */
SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Cryptographically Secure Random Number Generator");
MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures");
#if defined(RANDOM_DUMMY)
/*-
* Dummy "always block" pseudo algorithm, used when there is no real
* random(4) driver to provide a CSPRNG.
*/
static u_int
dummy_random_zero(void)
{
return (0);
}
static void
dummy_random(void)
{
}
struct random_algorithm random_alg_context = {
.ra_ident = "Dummy",
.ra_init_alg = NULL,
.ra_deinit_alg = NULL,
.ra_pre_read = dummy_random,
.ra_read = (random_alg_read_t *)dummy_random_zero,
.ra_write = (random_alg_write_t *)dummy_random_zero,
.ra_reseed = dummy_random,
.ra_seeded = (random_alg_seeded_t *)dummy_random_zero,
.ra_event_processor = NULL,
.ra_poolcount = 0,
};
#else /* !defined(RANDOM_DUMMY) */
LIST_HEAD(sources_head, random_sources);
static struct sources_head source_list = LIST_HEAD_INITIALIZER(source_list);
static u_int read_rate;
static void
random_alg_context_ra_init_alg(void *data)
{
random_alg_context.ra_init_alg(data);
p_random_alg_context = &random_alg_context;
p_random_alg_context->ra_init_alg(data);
#if defined(RANDOM_LOADABLE)
random_infra_init(READ_RANDOM_UIO, READ_RANDOM);
#endif
}
static void
random_alg_context_ra_deinit_alg(void *data)
{
random_alg_context.ra_deinit_alg(data);
#if defined(RANDOM_LOADABLE)
random_infra_uninit();
#endif
p_random_alg_context->ra_deinit_alg(data);
p_random_alg_context = NULL;
}
SYSINIT(random_device, SI_SUB_RANDOM, SI_ORDER_THIRD, random_alg_context_ra_init_alg, NULL);
SYSUNINIT(random_device, SI_SUB_RANDOM, SI_ORDER_THIRD, random_alg_context_ra_deinit_alg, NULL);
#endif /* defined(RANDOM_DUMMY) */
static struct selinfo rsel;
/*
@ -156,28 +123,28 @@ static int
randomdev_read(struct cdev *dev __unused, struct uio *uio, int flags)
{
return (read_random_uio(uio, (flags & O_NONBLOCK) != 0));
return (READ_RANDOM_UIO(uio, (flags & O_NONBLOCK) != 0));
}
int
read_random_uio(struct uio *uio, bool nonblock)
READ_RANDOM_UIO(struct uio *uio, bool nonblock)
{
uint8_t *random_buf;
int error, spamcount;
ssize_t read_len, total_read, c;
random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
random_alg_context.ra_pre_read();
p_random_alg_context->ra_pre_read();
error = 0;
spamcount = 0;
/* (Un)Blocking logic */
while (!random_alg_context.ra_seeded()) {
while (!p_random_alg_context->ra_seeded()) {
if (nonblock) {
error = EWOULDBLOCK;
break;
}
/* keep tapping away at the pre-read until we seed/unblock. */
random_alg_context.ra_pre_read();
p_random_alg_context->ra_pre_read();
/* Only bother the console every 10 seconds or so */
if (spamcount == 0)
printf("random: %s unblock wait\n", __func__);
@ -187,10 +154,7 @@ read_random_uio(struct uio *uio, bool nonblock)
break;
}
if (error == 0) {
#if !defined(RANDOM_DUMMY)
/* XXX: FIX!! Next line as an atomic operation? */
read_rate += (uio->uio_resid + sizeof(uint32_t))/sizeof(uint32_t);
#endif
read_rate_increment((uio->uio_resid + sizeof(uint32_t))/sizeof(uint32_t));
total_read = 0;
while (uio->uio_resid && !error) {
read_len = uio->uio_resid;
@ -203,7 +167,7 @@ read_random_uio(struct uio *uio, bool nonblock)
read_len = CEIL_TO_MULTIPLE(read_len, RANDOM_BLOCKSIZE);
/* Work in chunks page-sized or less */
read_len = MIN(read_len, PAGE_SIZE);
random_alg_context.ra_read(random_buf, read_len);
p_random_alg_context->ra_read(random_buf, read_len);
c = MIN(uio->uio_resid, read_len);
error = uiomove(random_buf, c, uio);
total_read += c;
@ -224,19 +188,16 @@ read_random_uio(struct uio *uio, bool nonblock)
* RANDOM_BLOCKSIZE bytes.
*/
u_int
read_random(void *random_buf, u_int len)
READ_RANDOM(void *random_buf, u_int len)
{
u_int read_len;
uint8_t local_buf[len + RANDOM_BLOCKSIZE];
KASSERT(random_buf != NULL, ("No suitable random buffer in %s", __func__));
random_alg_context.ra_pre_read();
p_random_alg_context->ra_pre_read();
/* (Un)Blocking logic; if not seeded, return nothing. */
if (random_alg_context.ra_seeded()) {
#if !defined(RANDOM_DUMMY)
/* XXX: FIX!! Next line as an atomic operation? */
read_rate += (len + sizeof(uint32_t))/sizeof(uint32_t);
#endif
if (p_random_alg_context->ra_seeded()) {
read_rate_increment((len + sizeof(uint32_t))/sizeof(uint32_t));
if (len > 0) {
/*
* Belt-and-braces.
@ -244,7 +205,7 @@ read_random(void *random_buf, u_int len)
* which is what the underlying generator is expecting.
*/
read_len = CEIL_TO_MULTIPLE(len, RANDOM_BLOCKSIZE);
random_alg_context.ra_read(local_buf, read_len);
p_random_alg_context->ra_read(local_buf, read_len);
memcpy(random_buf, local_buf, len);
}
} else
@ -252,6 +213,37 @@ read_random(void *random_buf, u_int len)
return (len);
}
static __inline void
randomdev_accumulate(uint8_t *buf, u_int count)
{
static u_int destination = 0;
static struct harvest_event event;
static struct randomdev_hash hash;
static uint32_t entropy_data[RANDOM_KEYSIZE_WORDS];
uint32_t timestamp;
int i;
/* Extra timing here is helpful to scrape scheduler jitter entropy */
randomdev_hash_init(&hash);
timestamp = (uint32_t)get_cyclecount();
randomdev_hash_iterate(&hash, &timestamp, sizeof(timestamp));
randomdev_hash_iterate(&hash, buf, count);
timestamp = (uint32_t)get_cyclecount();
randomdev_hash_iterate(&hash, &timestamp, sizeof(timestamp));
randomdev_hash_finish(&hash, entropy_data);
explicit_bzero(&hash, sizeof(hash));
for (i = 0; i < RANDOM_KEYSIZE_WORDS; i += sizeof(event.he_entropy)/sizeof(event.he_entropy[0])) {
event.he_somecounter = (uint32_t)get_cyclecount();
event.he_size = sizeof(event.he_entropy);
event.he_bits = event.he_size/8;
event.he_source = RANDOM_CACHED;
event.he_destination = destination++; /* Harmless cheating */
memcpy(event.he_entropy, entropy_data + i, sizeof(event.he_entropy));
p_random_alg_context->ra_event_processor(&event);
}
explicit_bzero(entropy_data, sizeof(entropy_data));
}
/* ARGSUSED */
static int
randomdev_write(struct cdev *dev __unused, struct uio *uio, int flags __unused)
@ -267,7 +259,7 @@ randomdev_write(struct cdev *dev __unused, struct uio *uio, int flags __unused)
error = uiomove(random_buf, c, uio);
if (error)
break;
random_alg_context.ra_write(random_buf, c);
randomdev_accumulate(random_buf, c);
tsleep(&random_alg_context, 0, "randwr", hz/10);
}
if (nbytes != uio->uio_resid && (error == ERESTART || error == EINTR))
@ -283,7 +275,7 @@ randomdev_poll(struct cdev *dev __unused, int events, struct thread *td __unused
{
if (events & (POLLIN | POLLRDNORM)) {
if (random_alg_context.ra_seeded())
if (p_random_alg_context->ra_seeded())
events &= (POLLIN | POLLRDNORM);
else
selrecord(td, &rsel);
@ -325,9 +317,6 @@ randomdev_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused,
void
random_source_register(struct random_source *rsource)
{
#if defined(RANDOM_DUMMY)
(void)rsource;
#else /* !defined(RANDOM_DUMMY) */
struct random_sources *rrs;
KASSERT(rsource != NULL, ("invalid input to %s", __func__));
@ -337,15 +326,11 @@ random_source_register(struct random_source *rsource)
printf("random: registering fast source %s\n", rsource->rs_ident);
LIST_INSERT_HEAD(&source_list, rrs, rrs_entries);
#endif /* defined(RANDOM_DUMMY) */
}
void
random_source_deregister(struct random_source *rsource)
{
#if defined(RANDOM_DUMMY)
(void)rsource;
#else /* !defined(RANDOM_DUMMY) */
struct random_sources *rrs = NULL;
KASSERT(rsource != NULL, ("invalid input to %s", __func__));
@ -356,41 +341,6 @@ random_source_deregister(struct random_source *rsource)
}
if (rrs != NULL)
free(rrs, M_ENTROPY);
#endif /* defined(RANDOM_DUMMY) */
}
#if !defined(RANDOM_DUMMY)
/*
* Run through all fast sources reading entropy for the given
* number of rounds, which should be a multiple of the number
* of entropy accumulation pools in use; 2 for Yarrow and 32
* for Fortuna.
*
* BEWARE!!!
* This function runs inside the RNG thread! Don't do anything silly!
*/
void
random_sources_feed(void)
{
uint32_t entropy[HARVESTSIZE];
struct random_sources *rrs;
u_int i, n, local_read_rate;
/*
* Step over all of live entropy sources, and feed their output
* to the system-wide RNG.
*/
/* XXX: FIX!! Next lines as an atomic operation? */
local_read_rate = read_rate;
read_rate = RANDOM_ALG_READ_RATE_MINIMUM;
LIST_FOREACH(rrs, &source_list, rrs_entries) {
for (i = 0; i < random_alg_context.ra_poolcount*local_read_rate; i++) {
n = rrs->rrs_source->rs_read(entropy, sizeof(entropy));
KASSERT((n > 0 && n <= sizeof(entropy)), ("very bad return from rs_read (= %d) in %s", n, __func__));
random_harvest_direct(entropy, n, (n*8)/2, rrs->rrs_source->rs_source);
}
}
explicit_bzero(entropy, sizeof(entropy));
}
static int
@ -414,7 +364,6 @@ random_source_handler(SYSCTL_HANDLER_ARGS)
SYSCTL_PROC(_kern_random, OID_AUTO, random_sources, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
NULL, 0, random_source_handler, "A",
"List of active fast entropy sources.");
#endif /* !defined(RANDOM_DUMMY) */
/* ARGSUSED */
static int
@ -449,3 +398,5 @@ static moduledata_t randomdev_mod = {
DECLARE_MODULE(random_device, randomdev_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
MODULE_VERSION(random_device, 1);
MODULE_DEPEND(random_device, crypto, 1, 1, 1);
MODULE_DEPEND(random_device, random_harvestq, 1, 1, 1);

View File

@ -55,16 +55,15 @@ random_check_uint_##name(SYSCTL_HANDLER_ARGS) \
MALLOC_DECLARE(M_ENTROPY);
#define RANDOM_ALG_READ_RATE_MINIMUM 32
#endif /* _KERNEL */
struct harvest_event;
typedef void random_alg_init_t(void *);
typedef void random_alg_deinit_t(void *);
typedef void random_alg_pre_read_t(void);
typedef void random_alg_read_t(uint8_t *, u_int);
typedef void random_alg_write_t(uint8_t *, u_int);
typedef int random_alg_seeded_t(void);
typedef bool random_alg_seeded_t(void);
typedef void random_alg_reseed_t(void);
typedef void random_alg_eventprocessor_t(struct harvest_event *);
@ -81,13 +80,11 @@ struct random_algorithm {
void (*ra_deinit_alg)(void *);
random_alg_pre_read_t *ra_pre_read;
random_alg_read_t *ra_read;
random_alg_write_t *ra_write;
random_alg_reseed_t *ra_reseed;
random_alg_seeded_t *ra_seeded;
random_alg_eventprocessor_t *ra_event_processor;
};
extern struct random_algorithm random_alg_context;
extern struct random_algorithm random_alg_context, *p_random_alg_context;
#ifdef _KERNEL
@ -97,22 +94,33 @@ extern struct random_algorithm random_alg_context;
* upon request.
*/
struct random_source {
const char *rs_ident;
enum random_entropy_source rs_source;
random_source_read_t *rs_read;
const char *rs_ident;
enum random_entropy_source rs_source;
random_source_read_t *rs_read;
};
#if !defined(RANDOM_DUMMY)
struct random_sources {
LIST_ENTRY(random_sources) rrs_entries;
struct random_source *rrs_source;
LIST_ENTRY(random_sources) rrs_entries;
struct random_source *rrs_source;
};
#endif /* !defined(RANDOM_DUMMY) */
LIST_HEAD(sources_head, random_sources);
extern struct sources_head source_list;
void random_source_register(struct random_source *);
void random_source_deregister(struct random_source *);
void random_sources_feed(void);
#if defined(RANDOM_LOADABLE)
extern struct sx randomdev_config_lock;
#define RANDOM_CONFIG_INIT_LOCK(x) sx_init(&randomdev_config_lock, "configuration change lock")
#define RANDOM_CONFIG_X_LOCK(x) sx_xlock(&randomdev_config_lock)
#define RANDOM_CONFIG_X_UNLOCK(x) sx_xunlock(&randomdev_config_lock)
#define RANDOM_CONFIG_S_LOCK(x) sx_slock(&randomdev_config_lock)
#define RANDOM_CONFIG_S_UNLOCK(x) sx_sunlock(&randomdev_config_lock)
#define RANDOM_CONFIG_DEINIT_LOCK(x) sx_destroy(&randomdev_config_lock)
void random_infra_init(int (*)(struct uio *, bool), u_int (*)(void *, u_int));
void random_infra_uninit(void);
#endif
#endif /* _KERNEL */

View File

@ -1,72 +0,0 @@
/*-
* Copyright (c) 2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/random.h>
#include <sys/systm.h>
#include <dev/random/randomdev.h>
#include "opt_random.h"
#if defined(RANDOM_DUMMY) || defined(RANDOM_YARROW)
#error "Cannot define any of RANDOM_DUMMY and RANDOM_YARROW without 'device random'"
#endif
/*-
* Dummy "not even here" device. Stub out all routines that the kernel would need.
*/
/* ARGSUSED */
u_int
read_random(void *random_buf __unused, u_int len __unused)
{
return (0);
}
/* ARGSUSED */
void
random_harvest_direct(const void *entropy __unused, u_int count __unused, u_int bits __unused, enum random_entropy_source origin __unused)
{
}
/* ARGSUSED */
void
random_harvest_queue(const void *entropy __unused, u_int count __unused, u_int bits __unused, enum random_entropy_source origin __unused)
{
}
/* ARGSUSED */
void
random_harvest_fast(const void *entropy __unused, u_int count __unused, u_int bits __unused, enum random_entropy_source origin __unused)
{
}

View File

@ -46,6 +46,7 @@ Where <alg> is YARROW or FORTUNA.
#include <sys/types.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <threads.h>
@ -171,35 +172,6 @@ RunHarvester(void *arg __unused)
return (0);
}
static int
WriteCSPRNG(void *threadid)
{
uint8_t *buf;
int i;
printf("Thread #1 starts\n");
for (i = 0; ; i++) {
if (stopseeding)
break;
buf = malloc(4096);
if (i % 1000 == 0)
printf("Thread write 1 - %d\n", i);
if (buf != NULL) {
printf("Thread 1 writing.\n");
random_alg_context.ra_write(buf, i);
free(buf);
}
usleep(1000000);
}
printf("Thread #1 ends\n");
thrd_exit(0);
return (0);
}
static int
ReadCSPRNG(void *threadid)
{
@ -271,7 +243,7 @@ main(int argc, char *argv[])
for (t = 0; t < NUM_THREADS; t++) {
printf("In main: creating thread %ld\n", t);
rc = thrd_create(&threads[t], (t == 0 ? RunHarvester : (t == 1 ? WriteCSPRNG : ReadCSPRNG)), NULL);
rc = thrd_create(&threads[t], (t == 0 ? RunHarvester : ReadCSPRNG), NULL);
if (rc != thrd_success) {
printf("ERROR; return code from thrd_create() is %d\n", rc);
exit(-1);

View File

@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
#include <dev/random/yarrow.h>
#else /* !_KERNEL */
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
@ -92,7 +93,7 @@ static struct yarrow_state {
u_int ysp_thresh; /* pool reseed threshhold */
struct randomdev_hash ysp_hash; /* accumulated entropy */
} ys_pool[RANDOM_YARROW_NPOOLS];/* pool[0] is fast, pool[1] is slow */
int ys_seeded;
bool ys_seeded;
/* Reseed lock */
mtx_t ys_mtx;
} yarrow_state;
@ -108,9 +109,7 @@ RANDOM_CHECK_UINT(slowoverthresh, 1, 5);
static void random_yarrow_pre_read(void);
static void random_yarrow_read(uint8_t *, u_int);
static void random_yarrow_write(uint8_t *, u_int);
static void random_yarrow_reseed(void);
static int random_yarrow_seeded(void);
static bool random_yarrow_seeded(void);
static void random_yarrow_process_event(struct harvest_event *);
static void random_yarrow_init_alg(void *);
static void random_yarrow_deinit_alg(void *);
@ -123,8 +122,6 @@ struct random_algorithm random_alg_context = {
.ra_deinit_alg = random_yarrow_deinit_alg,
.ra_pre_read = random_yarrow_pre_read,
.ra_read = random_yarrow_read,
.ra_write = random_yarrow_write,
.ra_reseed = random_yarrow_reseed,
.ra_seeded = random_yarrow_seeded,
.ra_event_processor = random_yarrow_process_event,
.ra_poolcount = RANDOM_YARROW_NPOOLS,
@ -141,7 +138,7 @@ random_yarrow_init_alg(void *unused __unused)
RANDOM_RESEED_INIT_LOCK();
/* Start unseeded, therefore blocked. */
yarrow_state.ys_seeded = 0;
yarrow_state.ys_seeded = false;
#ifdef _KERNEL
/*
* Yarrow parameters. Do not adjust these unless you have
@ -266,12 +263,14 @@ random_yarrow_reseed_internal(u_int fastslow)
RANDOM_RESEED_ASSERT_LOCK_OWNED();
#ifdef RANDOM_DEBUG
/* WARNING! This is dangerously tedious to do with mutexes held! */
printf("random: %s %s seeded = %d\n", __func__, (fastslow == RANDOM_YARROW_FAST ? "RANDOM_YARROW_FAST" : "RANDOM_YARROW_SLOW"), yarrow_state.ys_seeded);
printf("random: %s - fast - thresh %d,1 - ", __func__, yarrow_state.ys_pool[RANDOM_YARROW_FAST].ysp_thresh);
printf("random: %s ", __func__);
printf("type/pool = %s ", fastslow == RANDOM_YARROW_FAST ? "RANDOM_YARROW_FAST" : "RANDOM_YARROW_SLOW");
printf("seeded = %s\n", yarrow_state.ys_seeded ? "true" : "false");
printf("random: fast - thresh %d,1 - ", yarrow_state.ys_pool[RANDOM_YARROW_FAST].ysp_thresh);
for (i = RANDOM_START; i < ENTROPYSOURCE; i++)
printf(" %d", yarrow_state.ys_pool[RANDOM_YARROW_FAST].ysp_source_bits[i]);
printf("\n");
printf("random: %s - slow - thresh %d,%d - ", __func__, yarrow_state.ys_pool[RANDOM_YARROW_SLOW].ysp_thresh, yarrow_state.ys_slowoverthresh);
printf("random: slow - thresh %d,%d - ", yarrow_state.ys_pool[RANDOM_YARROW_SLOW].ysp_thresh, yarrow_state.ys_slowoverthresh);
for (i = RANDOM_START; i < ENTROPYSOURCE; i++)
printf(" %d", yarrow_state.ys_pool[RANDOM_YARROW_SLOW].ysp_source_bits[i]);
printf("\n");
@ -338,7 +337,7 @@ random_yarrow_reseed_internal(u_int fastslow)
#endif
/* Unblock the device if it was blocked due to being unseeded */
if (!yarrow_state.ys_seeded) {
yarrow_state.ys_seeded = 1;
yarrow_state.ys_seeded = true;
randomdev_unblock();
}
}
@ -395,47 +394,7 @@ random_yarrow_read(uint8_t *buf, u_int bytecount)
RANDOM_RESEED_UNLOCK();
}
/* Internal function to hand external entropy to the PRNG. */
void
random_yarrow_write(uint8_t *buf, u_int count)
{
static u_int destination = 0;
static struct harvest_event event;
struct randomdev_hash hash;
uint32_t entropy_data[RANDOM_KEYSIZE_WORDS], timestamp;
int i;
/* Extra timing here is helpful to scrape scheduler timing entropy */
randomdev_hash_init(&hash);
timestamp = (uint32_t)get_cyclecount();
randomdev_hash_iterate(&hash, &timestamp, sizeof(timestamp));
randomdev_hash_iterate(&hash, buf, count);
timestamp = (uint32_t)get_cyclecount();
randomdev_hash_iterate(&hash, &timestamp, sizeof(timestamp));
randomdev_hash_finish(&hash, entropy_data);
explicit_bzero(&hash, sizeof(hash));
for (i = 0; i < RANDOM_KEYSIZE_WORDS; i += sizeof(event.he_entropy)/sizeof(event.he_entropy[0])) {
event.he_somecounter = (uint32_t)get_cyclecount();
event.he_size = sizeof(event.he_entropy);
event.he_bits = event.he_size/8;
event.he_source = RANDOM_CACHED;
event.he_destination = destination++; /* Harmless cheating */
memcpy(event.he_entropy, entropy_data + i, sizeof(event.he_entropy));
random_yarrow_process_event(&event);
}
explicit_bzero(entropy_data, sizeof(entropy_data));
}
void
random_yarrow_reseed(void)
{
RANDOM_RESEED_LOCK();
random_yarrow_reseed_internal(RANDOM_YARROW_SLOW);
RANDOM_RESEED_UNLOCK();
}
int
bool
random_yarrow_seeded(void)
{

View File

@ -296,6 +296,9 @@ SUBDIR= \
${_qlxgbe} \
ral \
${_ralfw} \
${_random_fortuna} \
${_random_yarrow} \
${_random_other} \
rc4 \
${_rdma} \
${_rdrand_rng} \
@ -398,6 +401,9 @@ _autofs= autofs
.if exists(${.CURDIR}/../opencrypto)
_crypto= crypto
_cryptodev= cryptodev
_random_fortuna=random_fortuna
_random_yarrow= random_yarrow
_random_other= random_other
.endif
.endif

View File

@ -0,0 +1,11 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../dev/random
KMOD = random_fortuna
SRCS = randomdev.c hash.c fortuna.c
SRCS += opt_param.h bus_if.h device_if.h
SRCS += opt_ddb.h
CFLAGS += -DRANDOM_LOADABLE
.include <bsd.kmod.mk>

View File

@ -0,0 +1,11 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../dev/random
KMOD = random_OTHER
SRCS = randomdev.c hash.c other_algorithm.c
SRCS += opt_param.h bus_if.h device_if.h
SRCS += opt_ddb.h
CFLAGS += -DRANDOM_LOADABLE
.include <bsd.kmod.mk>

View File

@ -0,0 +1,11 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../dev/random
KMOD = random_yarrow
SRCS = randomdev.c hash.c yarrow.c
SRCS += opt_param.h bus_if.h device_if.h
SRCS += opt_ddb.h
CFLAGS += -DRANDOM_LOADABLE
.include <bsd.kmod.mk>

View File

@ -33,10 +33,29 @@
#include <sys/types.h>
#include "opt_random.h"
#if defined(RANDOM_LOADABLE) && defined(RANDOM_YARROW)
#error "Cannot define both RANDOM_LOADABLE and RANDOM_YARROW"
#endif
struct uio;
#if defined(DEV_RANDOM)
u_int read_random(void *, u_int);
int read_random_uio(struct uio *, bool);
#else
static __inline int
read_random_uio(void *a __unused, u_int b __unused)
{
return (0);
}
static __inline u_int
read_random(void *a __unused, u_int b __unused)
{
return (0);
}
#endif
/*
* Note: if you add or remove members of random_entropy_source, remember to also update the
@ -76,15 +95,15 @@ enum random_entropy_source {
#define RANDOM_HARVEST_EVERYTHING_MASK ((1 << (RANDOM_ENVIRONMENTAL_END + 1)) - 1)
#if defined(RANDOM_DUMMY)
#define random_harvest_queue(a, b, c, d) do {} while (0)
#define random_harvest_fast(a, b, c, d) do {} while (0)
#define random_harvest_direct(a, b, c, d) do {} while (0)
#else /* !defined(RANDOM_DUMMY) */
#if defined(DEV_RANDOM)
void random_harvest_queue(const void *, u_int, u_int, enum random_entropy_source);
void random_harvest_fast(const void *, u_int, u_int, enum random_entropy_source);
void random_harvest_direct(const void *, u_int, u_int, enum random_entropy_source);
#endif /* defined(RANDOM_DUMMY) */
#else
#define random_harvest_queue(a, b, c, d) do {} while (0)
#define random_harvest_fast(a, b, c, d) do {} while (0)
#define random_harvest_direct(a, b, c, d) do {} while (0)
#endif
#endif /* _KERNEL */