summaryrefslogtreecommitdiffstats
path: root/sys/dev/random
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/random')
-rw-r--r--sys/dev/random/harvest.c137
-rw-r--r--sys/dev/random/hash.c79
-rw-r--r--sys/dev/random/hash.h44
-rw-r--r--sys/dev/random/randomdev.c445
-rw-r--r--sys/dev/random/randomdev.h83
-rw-r--r--sys/dev/random/yarrow.c338
-rw-r--r--sys/dev/random/yarrow.h59
7 files changed, 1185 insertions, 0 deletions
diff --git a/sys/dev/random/harvest.c b/sys/dev/random/harvest.c
new file mode 100644
index 0000000..b6f3fba
--- /dev/null
+++ b/sys/dev/random/harvest.c
@@ -0,0 +1,137 @@
+/*-
+ * Copyright (c) 2000 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$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/poll.h>
+#include <sys/selinfo.h>
+#include <sys/sysctl.h>
+#include <sys/random.h>
+
+#include <machine/cpu.h>
+
+#include <dev/random/randomdev.h>
+
+static int read_random_phony(void *, int);
+
+/* Structure holding the desired entropy sources */
+struct harvest_select harvest = { 0, 0, 0 };
+
+/* hold the address of the routine which is actually called if
+ * the randomdev is loaded
+ */
+static void (*reap_func)(u_int64_t, void *, u_int, u_int, u_int, enum esource)
+ = NULL;
+static int (*read_func)(void *, int) = read_random_phony;
+
+/* Initialise the harvester at load time */
+void
+random_init_harvester(void (*reaper)(u_int64_t, void *, u_int, u_int, u_int,
+ enum esource), int (*reader)(void *, int))
+{
+ reap_func = reaper;
+ read_func = reader;
+}
+
+/* Deinitialise the harvester at unload time */
+void
+random_deinit_harvester(void)
+{
+ reap_func = NULL;
+ read_func = read_random_phony;
+}
+
+/* Entropy harvesting routine. This is supposed to be fast; do
+ * not do anything slow in here!
+ * Implemented as in indirect call to allow non-inclusion of
+ * the entropy device.
+ */
+void
+random_harvest(void *entropy, u_int count, u_int bits, u_int frac,
+ enum esource origin)
+{
+ if (reap_func)
+ (*reap_func)(get_cyclecount(), entropy, count, bits, frac,
+ origin);
+}
+
+/* Userland-visible version of read_random */
+int
+read_random(void *buf, int count)
+{
+ return (*read_func)(buf, count);
+}
+
+/* If the entropy device is not loaded, make a token effort to
+ * provide _some_ kind of randomness. This should only be used
+ * inside other RNG's, like arc4random(9).
+ */
+static int
+read_random_phony(void *buf, int count)
+{
+ u_long randval;
+ int size, i;
+ static int initialised = 0;
+
+ /* Try to give random(9) a half decent initialisation
+ * DO NOT make the mistake of thinking this is secure!!
+ */
+ if (!initialised)
+ srandom((u_long)get_cyclecount());
+
+ /* Fill buf[] with random(9) output */
+ for (i = 0; i < count; i+= (int)sizeof(u_long)) {
+ randval = random();
+ size = (count - i) < (int)sizeof(u_long)
+ ? (count - i)
+ : sizeof(u_long);
+ memcpy(&((char *)buf)[i], &randval, (size_t)size);
+ }
+
+ return count;
+}
+
+/* Helper routine to enable kthread_exit() to work while the module is
+ * being (or has been) unloaded.
+ * This routine is in this file because it is always linked into the kernel,
+ * and will thus never be unloaded. This is critical for unloadable modules
+ * that have threads.
+ */
+void
+random_set_wakeup_exit(void *control)
+{
+ wakeup(control);
+ mtx_lock(&Giant);
+ kthread_exit(0);
+ /* NOTREACHED */
+}
diff --git a/sys/dev/random/hash.c b/sys/dev/random/hash.c
new file mode 100644
index 0000000..b6bf4b2
--- /dev/null
+++ b/sys/dev/random/hash.c
@@ -0,0 +1,79 @@
+/*-
+ * Copyright (c) 2000 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$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <crypto/rijndael/rijndael.h>
+#include <crypto/sha2/sha2.h>
+
+#include <dev/random/hash.h>
+
+/* initialise the hash */
+void
+yarrow_hash_init(struct yarrowhash *context)
+{
+ SHA256_Init(&context->sha);
+}
+
+/* iterate the hash */
+void
+yarrow_hash_iterate(struct yarrowhash *context, void *data, size_t size)
+{
+ SHA256_Update(&context->sha, data, size);
+}
+
+/* Conclude by returning the hash in the supplied /buf/ which must be
+ * KEYSIZE bytes long.
+ */
+void
+yarrow_hash_finish(struct yarrowhash *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.
+ */
+void
+yarrow_encrypt_init(struct yarrowkey *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/.
+ */
+void
+yarrow_encrypt(struct yarrowkey *context, void *d_in, void *d_out)
+{
+ rijndael_blockEncrypt(&context->cipher, &context->key, d_in,
+ KEYSIZE*8, d_out);
+}
diff --git a/sys/dev/random/hash.h b/sys/dev/random/hash.h
new file mode 100644
index 0000000..b307bfc
--- /dev/null
+++ b/sys/dev/random/hash.h
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2000 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$
+ */
+
+#define KEYSIZE 32 /* (in bytes) 32 bytes == 256 bits */
+
+struct yarrowhash { /* Big! Make static! */
+ SHA256_CTX sha;
+};
+
+struct yarrowkey { /* 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 *);
diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c
new file mode 100644
index 0000000..d965cbc
--- /dev/null
+++ b/sys/dev/random/randomdev.c
@@ -0,0 +1,445 @@
+/*-
+ * Copyright (c) 2000 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$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/fcntl.h>
+#include <sys/filio.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/malloc.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>
+#include <sys/uio.h>
+#include <sys/unistd.h>
+#include <sys/vnode.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+
+#include <dev/random/randomdev.h>
+
+static d_open_t random_open;
+static d_close_t random_close;
+static d_read_t random_read;
+static d_write_t random_write;
+static d_ioctl_t random_ioctl;
+static d_poll_t random_poll;
+
+#define CDEV_MAJOR 2
+#define RANDOM_MINOR 3
+
+static struct cdevsw random_cdevsw = {
+ /* open */ random_open,
+ /* close */ random_close,
+ /* read */ random_read,
+ /* write */ random_write,
+ /* ioctl */ random_ioctl,
+ /* poll */ random_poll,
+ /* mmap */ nommap,
+ /* strategy */ nostrategy,
+ /* name */ "random",
+ /* maj */ CDEV_MAJOR,
+ /* dump */ nodump,
+ /* psize */ nopsize,
+ /* flags */ 0,
+ /* kqfilter */ NULL
+};
+
+static void random_kthread(void *);
+static void random_harvest_internal(u_int64_t, void *, u_int, u_int, u_int, enum esource);
+static void random_write_internal(void *, int);
+
+/* Ring buffer holding harvested entropy */
+static struct harvestring {
+ volatile u_int head;
+ volatile u_int tail;
+ struct harvest data[HARVEST_RING_SIZE];
+} harvestring;
+
+static struct random_systat {
+ u_int seeded; /* 0 causes blocking 1 allows normal output */
+ u_int burst; /* number of events to do before sleeping */
+ struct selinfo rsel; /* For poll(2) */
+} random_systat;
+
+/* <0 to end the kthread, 0 to let it run */
+static int random_kthread_control = 0;
+
+static struct proc *random_kthread_proc;
+
+/* For use with make_dev(9)/destroy_dev(9). */
+static dev_t random_dev;
+static dev_t urandom_dev;
+
+/* ARGSUSED */
+static int
+random_check_boolean(SYSCTL_HANDLER_ARGS)
+{
+ if (oidp->oid_arg1 != NULL && *(u_int *)(oidp->oid_arg1) != 0)
+ *(u_int *)(oidp->oid_arg1) = 1;
+ return sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
+}
+
+RANDOM_CHECK_UINT(burst, 0, 20);
+
+SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW,
+ 0, "Random Number Generator");
+SYSCTL_NODE(_kern_random, OID_AUTO, sys, CTLFLAG_RW,
+ 0, "Entropy Device Parameters");
+SYSCTL_PROC(_kern_random_sys, OID_AUTO, seeded,
+ CTLTYPE_INT|CTLFLAG_RW, &random_systat.seeded, 1,
+ random_check_boolean, "I", "Seeded State");
+SYSCTL_PROC(_kern_random_sys, OID_AUTO, burst,
+ CTLTYPE_INT|CTLFLAG_RW, &random_systat.burst, 20,
+ random_check_uint_burst, "I", "Harvest Burst Size");
+SYSCTL_NODE(_kern_random_sys, OID_AUTO, harvest, CTLFLAG_RW,
+ 0, "Entropy Sources");
+SYSCTL_PROC(_kern_random_sys_harvest, OID_AUTO, ethernet,
+ CTLTYPE_INT|CTLFLAG_RW, &harvest.ethernet, 0,
+ random_check_boolean, "I", "Harvest NIC entropy");
+SYSCTL_PROC(_kern_random_sys_harvest, OID_AUTO, point_to_point,
+ CTLTYPE_INT|CTLFLAG_RW, &harvest.point_to_point, 0,
+ random_check_boolean, "I", "Harvest serial net entropy");
+SYSCTL_PROC(_kern_random_sys_harvest, OID_AUTO, interrupt,
+ CTLTYPE_INT|CTLFLAG_RW, &harvest.interrupt, 0,
+ random_check_boolean, "I", "Harvest IRQ entropy");
+SYSCTL_PROC(_kern_random_sys_harvest, OID_AUTO, swi,
+ CTLTYPE_INT|CTLFLAG_RW, &harvest.swi, 0,
+ random_check_boolean, "I", "Harvest SWI entropy");
+
+/* ARGSUSED */
+static int
+random_open(dev_t dev __unused, int flags, int fmt __unused, struct thread *td)
+{
+ int error;
+
+ if (flags & FWRITE) {
+ error = suser(td);
+ if (error)
+ return (error);
+ error = securelevel_gt(td->td_ucred, 0);
+ if (error)
+ return (error);
+ }
+ return 0;
+}
+
+/* ARGSUSED */
+static int
+random_close(dev_t dev __unused, int flags, int fmt __unused, struct thread *td)
+{
+ if (flags & FWRITE) {
+ if (!(suser(td) ||
+ securelevel_gt(td->td_ucred, 0)))
+ random_reseed();
+ }
+ return 0;
+}
+
+/* ARGSUSED */
+static int
+random_read(dev_t dev __unused, struct uio *uio, int flag)
+{
+ int c, ret;
+ int error = 0;
+ void *random_buf;
+
+ while (!random_systat.seeded) {
+ if (flag & IO_NDELAY)
+ error = EWOULDBLOCK;
+ else
+ error = tsleep(&random_systat, PUSER|PCATCH,
+ "block", 0);
+ if (error != 0)
+ return error;
+ }
+ c = uio->uio_resid < PAGE_SIZE ? uio->uio_resid : PAGE_SIZE;
+ random_buf = (void *)malloc((u_long)c, M_TEMP, M_WAITOK);
+ while (uio->uio_resid > 0 && error == 0) {
+ ret = read_random_real(random_buf, c);
+ error = uiomove(random_buf, ret, uio);
+ }
+ free(random_buf, M_TEMP);
+ return error;
+}
+
+/* ARGSUSED */
+static int
+random_write(dev_t dev __unused, struct uio *uio, int flag __unused)
+{
+ int c;
+ int error;
+ void *random_buf;
+
+ error = 0;
+ random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
+ while (uio->uio_resid > 0) {
+ c = (int)(uio->uio_resid < PAGE_SIZE
+ ? uio->uio_resid
+ : PAGE_SIZE);
+ error = uiomove(random_buf, c, uio);
+ if (error)
+ break;
+ random_write_internal(random_buf, c);
+ }
+ free(random_buf, M_TEMP);
+ return error;
+}
+
+/* ARGSUSED */
+static int
+random_ioctl(dev_t dev __unused, u_long cmd, caddr_t addr __unused,
+ int flags __unused, struct thread *td __unused)
+{
+ switch (cmd) {
+ /* Really handled in upper layer */
+ case FIOASYNC:
+ case FIONBIO:
+ return 0;
+ default:
+ return ENOTTY;
+ }
+}
+
+/* ARGSUSED */
+static int
+random_poll(dev_t dev __unused, int events, struct thread *td)
+{
+ int revents;
+
+ revents = 0;
+ if (events & (POLLIN | POLLRDNORM)) {
+ if (random_systat.seeded)
+ revents = events & (POLLIN | POLLRDNORM);
+ else
+ selrecord(td, &random_systat.rsel);
+ }
+ return revents;
+}
+
+/* ARGSUSED */
+static int
+random_modevent(module_t mod __unused, int type, void *data __unused)
+{
+ int error;
+
+ switch(type) {
+ case MOD_LOAD:
+ random_init();
+
+ /* This can be turned off by the very paranoid
+ * a reseed will turn it back on.
+ */
+ random_systat.seeded = 1;
+
+ /* Number of envents to process off the harvest
+ * queue before giving it a break and sleeping
+ */
+ random_systat.burst = 20;
+
+ /* Initialise the harvest ringbuffer */
+ harvestring.head = 0;
+ harvestring.tail = 0;
+
+ if (bootverbose)
+ printf("random: <entropy source>\n");
+ random_dev = make_dev(&random_cdevsw, RANDOM_MINOR, UID_ROOT,
+ GID_WHEEL, 0666, "random");
+ urandom_dev = make_dev_alias(random_dev, "urandom");
+
+ /* Start the hash/reseed thread */
+ error = kthread_create(random_kthread, NULL,
+ &random_kthread_proc, RFHIGHPID, 0, "random");
+ if (error != 0)
+ return error;
+
+ /* Register the randomness harvesting routine */
+ random_init_harvester(random_harvest_internal,
+ read_random_real);
+
+ return 0;
+
+ case MOD_UNLOAD:
+ /* Deregister the randomness harvesting routine */
+ random_deinit_harvester();
+
+ /* Command the hash/reseed thread to end and
+ * wait for it to finish
+ */
+ random_kthread_control = -1;
+ tsleep((void *)&random_kthread_control, PUSER, "term", 0);
+
+ random_deinit();
+
+ destroy_dev(random_dev);
+ destroy_dev(urandom_dev);
+ return 0;
+
+ case MOD_SHUTDOWN:
+ return 0;
+
+ default:
+ return EOPNOTSUPP;
+ }
+}
+
+DEV_MODULE(random, random_modevent, NULL);
+
+/* ARGSUSED */
+static void
+random_kthread(void *arg __unused)
+{
+ struct harvest *event;
+ u_int newtail, burst;
+
+ /* Drain the harvest queue (in 'burst' size chunks,
+ * if 'burst' > 0. If 'burst' == 0, then completely
+ * drain the queue.
+ */
+ for (burst = 0; ; burst++) {
+
+ if ((harvestring.tail == harvestring.head) ||
+ (random_systat.burst && burst == random_systat.burst)) {
+ tsleep(&harvestring, PUSER, "sleep", hz/10);
+ burst = 0;
+
+ }
+ else {
+
+ /* Suck a harvested entropy event out of the queue and
+ * hand it to the event processor
+ */
+
+ newtail = (harvestring.tail + 1) & HARVEST_RING_MASK;
+ event = &harvestring.data[harvestring.tail];
+
+ /* Bump the ring counter. This action is assumed
+ * to be atomic.
+ */
+ harvestring.tail = newtail;
+
+ random_process_event(event);
+
+ }
+
+ /* Is the thread scheduled for a shutdown? */
+ if (random_kthread_control != 0) {
+#ifdef DEBUG
+ printf("Random kthread setting terminate\n");
+#endif
+ random_set_wakeup_exit(&random_kthread_control);
+ /* NOTREACHED */
+ break;
+ }
+
+ }
+
+}
+
+/* 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, void *entropy, u_int count,
+ u_int bits, u_int frac, enum esource origin)
+{
+ struct harvest *pharvest;
+ u_int newhead;
+
+ newhead = (harvestring.head + 1) & HARVEST_RING_MASK;
+
+ if (newhead != harvestring.tail) {
+
+ /* Add the harvested data to the ring buffer */
+
+ pharvest = &harvestring.data[harvestring.head];
+
+ /* Stuff the harvested data into the ring */
+ pharvest->somecounter = somecounter;
+ count = count > HARVESTSIZE ? HARVESTSIZE : count;
+ memcpy(pharvest->entropy, entropy, count);
+ pharvest->size = count;
+ pharvest->bits = bits;
+ pharvest->frac = frac;
+ pharvest->source =
+ origin < ENTROPYSOURCE ? origin : RANDOM_START;
+
+ /* Bump the ring counter. This action is assumed
+ * to be atomic.
+ */
+ harvestring.head = newhead;
+
+ }
+
+}
+
+static void
+random_write_internal(void *buf, int count)
+{
+ int i;
+
+ /* Break the input up into HARVESTSIZE chunks.
+ * The writer has too much control here, so "estimate" the
+ * the entropy as zero.
+ */
+ for (i = 0; i < count; i += HARVESTSIZE) {
+ random_harvest_internal(get_cyclecount(), (char *)buf + i,
+ HARVESTSIZE, 0, 0, RANDOM_WRITE);
+ }
+
+ /* Maybe the loop iterated at least once */
+ if (i > count)
+ i -= HARVESTSIZE;
+
+ /* Get the last bytes even if the input length is not
+ * a multiple of HARVESTSIZE.
+ */
+ count %= HARVESTSIZE;
+ if (count) {
+ random_harvest_internal(get_cyclecount(), (char *)buf + i,
+ (u_int)count, 0, 0, RANDOM_WRITE);
+ }
+}
+
+void
+random_unblock(void)
+{
+ if (!random_systat.seeded) {
+ random_systat.seeded = 1;
+ selwakeup(&random_systat.rsel);
+ wakeup(&random_systat);
+ }
+}
diff --git a/sys/dev/random/randomdev.h b/sys/dev/random/randomdev.h
new file mode 100644
index 0000000..359dc26
--- /dev/null
+++ b/sys/dev/random/randomdev.h
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 2001 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 header contains only those definitions that are global
+ * and non algorithm-specific for the entropy processor
+ */
+
+/* #define ENTROPYSOURCE nn entropy sources (actually classes)
+ * This is properly defined in
+ * 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)
+
+#define HARVESTSIZE 16 /* max size of each harvested entropy unit */
+
+SYSCTL_DECL(_kern_random);
+
+/* These are used to queue harvested packets of entropy. The entropy
+ * buffer size is pretty arbitrary.
+ */
+struct harvest {
+ u_int64_t somecounter; /* fast counter for clock jitter */
+ u_char entropy[HARVESTSIZE]; /* the harvested entropy */
+ u_int size, bits, frac; /* stats about the entropy */
+ enum esource source; /* stats about the entropy */
+};
+
+void random_init(void);
+void random_deinit(void);
+void random_init_harvester(void (*)(u_int64_t, void *, u_int, u_int, u_int, enum esource), int (*)(void *, int));
+void random_deinit_harvester(void);
+void random_set_wakeup_exit(void *);
+void random_process_event(struct harvest *event);
+void random_reseed(void);
+void random_unblock(void);
+
+int read_random_real(void *, int);
+
+/* If this was c++, this would be a template */
+#define RANDOM_CHECK_UINT(name, min, max) \
+static int \
+random_check_uint_##name(SYSCTL_HANDLER_ARGS) \
+{ \
+ if (oidp->oid_arg1 != NULL) { \
+ if (*(u_int *)(oidp->oid_arg1) <= (min)) \
+ *(u_int *)(oidp->oid_arg1) = (min); \
+ else if (*(u_int *)(oidp->oid_arg1) > (max)) \
+ *(u_int *)(oidp->oid_arg1) = (max); \
+ } \
+ return sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, \
+ req); \
+}
diff --git a/sys/dev/random/yarrow.c b/sys/dev/random/yarrow.c
new file mode 100644
index 0000000..304de5d
--- /dev/null
+++ b/sys/dev/random/yarrow.c
@@ -0,0 +1,338 @@
+/*-
+ * Copyright (c) 2000 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$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/random.h>
+#include <sys/sysctl.h>
+
+#include <crypto/rijndael/rijndael.h>
+#include <crypto/sha2/sha2.h>
+
+#include <dev/random/hash.h>
+#include <dev/random/randomdev.h>
+#include <dev/random/yarrow.h>
+
+/* #define DEBUG */
+
+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(slowoverthresh, 1, 5);
+
+/* Structure holding the entropy state */
+static struct random_state random_state;
+
+SYSCTL_NODE(_kern_random, OID_AUTO, yarrow, CTLFLAG_RW, 0, "Yarrow Parameters");
+SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, gengateinterval,
+ CTLTYPE_INT|CTLFLAG_RW, &random_state.gengateinterval, 10,
+ random_check_uint_gengateinterval, "I", "Generator Gate Interval");
+SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, bins,
+ CTLTYPE_INT|CTLFLAG_RW, &random_state.bins, 10,
+ random_check_uint_bins, "I", "Execution time tuner");
+SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, fastthresh,
+ CTLTYPE_INT|CTLFLAG_RW, &random_state.pool[0].thresh, (3*BLOCKSIZE)/4,
+ random_check_uint_fastthresh, "I", "Fast reseed threshold");
+SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, slowthresh,
+ CTLTYPE_INT|CTLFLAG_RW, &random_state.pool[1].thresh, BLOCKSIZE,
+ random_check_uint_slowthresh, "I", "Slow reseed threshold");
+SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, slowoverthresh,
+ CTLTYPE_INT|CTLFLAG_RW, &random_state.slowoverthresh, 2,
+ random_check_uint_slowoverthresh, "I", "Slow over-threshold reseed");
+
+static void generator_gate(void);
+static void reseed(u_int);
+
+/* The reseed thread mutex */
+static struct mtx random_reseed_mtx;
+
+/* Process a single stochastic event off the harvest queue */
+void
+random_process_event(struct harvest *event)
+{
+ u_int pl, overthreshhold[2];
+ struct source *source;
+ enum esource src;
+
+ /* 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,
+ sizeof(event->entropy));
+ yarrow_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;
+
+ /* Count the over-threshold sources in each pool */
+ for (pl = 0; pl < 2; pl++) {
+ overthreshhold[pl] = 0;
+ for (src = RANDOM_START; src < ENTROPYSOURCE; src++) {
+ if (random_state.pool[pl].source[src].bits
+ > random_state.pool[pl].thresh)
+ overthreshhold[pl]++;
+ }
+ }
+
+ /* if any fast source over threshhold, reseed */
+ if (overthreshhold[FAST])
+ reseed(FAST);
+
+ /* if enough slow sources are over threshhold, reseed */
+ if (overthreshhold[SLOW] >= random_state.slowoverthresh)
+ reseed(SLOW);
+
+ /* Invert the fast/slow pool selector bit */
+ random_state.which = !random_state.which;
+}
+
+void
+random_init(void)
+{
+ int i;
+
+ /* Yarrow parameters. Do not adjust these unless you have
+ * have a very good clue about what they do!
+ */
+ random_state.gengateinterval = 10;
+ random_state.bins = 10;
+ random_state.pool[0].thresh = (3*BLOCKSIZE)/4;
+ random_state.pool[1].thresh = BLOCKSIZE;
+ 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);
+
+ /* Clear the counter */
+ for (i = 0; i < 4; i++)
+ random_state.counter[i] = 0;
+
+ /* Set up a lock for the reseed process */
+ mtx_init(&random_reseed_mtx, "random reseed", NULL, MTX_DEF);
+}
+
+void
+random_deinit(void)
+{
+ mtx_destroy(&random_reseed_mtx);
+}
+
+static void
+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];
+ u_int i;
+ enum esource j;
+
+#ifdef DEBUG
+ printf("Reseed type %d\n", fastslow);
+#endif
+
+ /* The reseed task must not be jumped on */
+ mtx_lock(&random_reseed_mtx);
+
+ /* 1. Hash the accumulated entropy into v[0] */
+
+ yarrow_hash_init(&context);
+ /* Feed the slow pool hash in if slow */
+ if (fastslow == SLOW)
+ yarrow_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]);
+
+ /* 2. Compute hash values for all v. _Supposed_ to be computationally
+ * intensive.
+ */
+
+ if (random_state.bins > TIMEBIN)
+ random_state.bins = TIMEBIN;
+ for (i = 1; i < random_state.bins; i++) {
+ yarrow_hash_init(&context);
+ /* v[i] #= h(v[i - 1]) */
+ yarrow_hash_iterate(&context, v[i - 1], KEYSIZE);
+ /* v[i] #= h(v[0]) */
+ yarrow_hash_iterate(&context, v[0], KEYSIZE);
+ /* v[i] #= h(i) */
+ yarrow_hash_iterate(&context, &i, sizeof(u_int));
+ /* Return the hashval */
+ yarrow_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);
+ 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);
+
+ /* 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));
+
+ /* 5. Reset entropy estimate accumulators to zero */
+
+ for (i = 0; i <= fastslow; i++) {
+ for (j = RANDOM_START; j < ENTROPYSOURCE; j++) {
+ random_state.pool[i].source[j].bits = 0;
+ random_state.pool[i].source[j].frac = 0;
+ }
+ }
+
+ /* 6. Wipe memory of intermediate values */
+
+ memset((void *)v, 0, sizeof(v));
+ memset((void *)temp, 0, sizeof(temp));
+ memset((void *)hash, 0, sizeof(hash));
+
+ /* 7. Dump to seed file */
+ /* XXX Not done here yet */
+
+ /* Release the reseed mutex */
+ mtx_unlock(&random_reseed_mtx);
+
+#ifdef DEBUG
+ printf("Reseed finish\n");
+#endif
+
+ /* Unblock the device if it was blocked due to being unseeded */
+ random_unblock();
+}
+
+/* Internal function to return processed entropy from the PRNG */
+int
+read_random_real(void *buf, int count)
+{
+ static int cur = 0;
+ static int gate = 1;
+ static u_char genval[KEYSIZE];
+ int i;
+ int retval;
+
+ /* The reseed task must not be jumped on */
+ mtx_lock(&random_reseed_mtx);
+
+ if (gate) {
+ generator_gate();
+ random_state.outputblocks = 0;
+ gate = 0;
+ }
+ if (count > 0 && (size_t)count >= sizeof(random_state.counter)) {
+ 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);
+ memcpy((char *)buf + i, genval,
+ sizeof(random_state.counter));
+ if (++random_state.outputblocks >=
+ random_state.gengateinterval) {
+ generator_gate();
+ random_state.outputblocks = 0;
+ }
+ retval += (int)sizeof(random_state.counter);
+ }
+ }
+ else {
+ if (!cur) {
+ random_state.counter[0]++;
+ yarrow_encrypt(&random_state.key, random_state.counter,
+ genval);
+ memcpy(buf, genval, (size_t)count);
+ cur = (int)sizeof(random_state.counter) - count;
+ if (++random_state.outputblocks >=
+ random_state.gengateinterval) {
+ generator_gate();
+ random_state.outputblocks = 0;
+ }
+ retval = count;
+ }
+ else {
+ retval = cur < count ? cur : count;
+ memcpy(buf,
+ &genval[(int)sizeof(random_state.counter) - cur],
+ (size_t)retval);
+ cur -= retval;
+ }
+ }
+ mtx_unlock(&random_reseed_mtx);
+ return retval;
+}
+
+static void
+generator_gate(void)
+{
+ u_int i;
+ u_char temp[KEYSIZE];
+
+#ifdef DEBUG
+ printf("Generator gate\n");
+#endif
+
+ for (i = 0; i < KEYSIZE; i += sizeof(random_state.counter)) {
+ random_state.counter[0]++;
+ yarrow_encrypt(&random_state.key, random_state.counter,
+ &(temp[i]));
+ }
+
+ yarrow_encrypt_init(&random_state.key, temp);
+ memset((void *)temp, 0, KEYSIZE);
+
+#ifdef DEBUG
+ printf("Generator gate finish\n");
+#endif
+}
+
+/* Helper routine to perform explicit reseeds */
+void
+random_reseed(void)
+{
+ reseed(SLOW);
+}
diff --git a/sys/dev/random/yarrow.h b/sys/dev/random/yarrow.h
new file mode 100644
index 0000000..2fc7be2
--- /dev/null
+++ b/sys/dev/random/yarrow.h
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2000 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 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 */
+};
OpenPOWER on IntegriCloud