Sorry for my absence, quite a bit happened to me in real life, but I'm
back with another entropy patch (hopefully ready to finally see a
version make it into CVS). This patch properly implements quality
control, and quality improvement, as well as cleaned up source. The
driver itself can be used with streamio
(settrans /dev/random /hurd/streamio entropy).
That being said, there appears to be a bug in the latest OpenSSH that
prevents it from opening /dev/random if its a translator (I tried both
my driver, marcus's, and even trying a symlink from /dev/hd1
to /dev/random, all resulting with the same error: PRNG not seeded).
Michael
? INSTALL
? Makefile.in
? aclocal.m4
? autom4te.cache
? build
? build-aux
? config.h.in
? configure
? entropy_patch.diff
? doc/mach.info
? doc/mach.info-1
? doc/mach.info-2
? doc/stamp-vti
? doc/version.texi
Index: Makefrag.am
===================================================================
RCS file: /sources/hurd/gnumach/Attic/Makefrag.am,v
retrieving revision 1.1.2.12
diff -u -r1.1.2.12 Makefrag.am
--- Makefrag.am 2 Jun 2007 13:23:21 -0000 1.1.2.12
+++ Makefrag.am 28 Aug 2007 11:24:38 -0000
@@ -292,6 +292,14 @@
device/kmsg.h
endif
+#
+# kernel entrophy generator device
+
+if enable_entropy
+libkernel_a_SOURCES += \
+ device/entropy.c
+ device/entropy.h
+endif
#
# Version number.
Index: configfrag.ac
===================================================================
RCS file: /sources/hurd/gnumach/Attic/configfrag.ac,v
retrieving revision 1.1.2.7
diff -u -r1.1.2.7 configfrag.ac
--- configfrag.ac 4 Aug 2007 18:50:19 -0000 1.1.2.7
+++ configfrag.ac 28 Aug 2007 11:24:38 -0000
@@ -129,10 +129,21 @@
AM_CONDITIONAL([enable_kmsg], [false])
[fi]
+
+AC_ARG_ENABLE([entropy],
+ AS_HELP_STRING([--disable-entropy], [disable use of entropy device]))
+[if [ x"$enable_entropy" != xno ]; then]
+ AC_DEFINE([MACH_ENTROPY], [], [enable use of entropy device])
+ AM_CONDITIONAL([enable_entropy], [true])
+[else]
+ AM_CONDITIONAL([enable_entropy], [false])
+[fi]
+
+
#
# Set up `SYSTYPE/SYSTYPE' and `SYSTYPE/include/mach/SYSTYPE' links.
#
-
+
# `${file}' and `$file' have different meanings here with respect to having the
# files in the referenced directory considered for `make dist' or not. See
# <http://lists.gnu.org/archive/html/bug-automake/2006-11/msg00027.html>.
Index: device/blkio.c
===================================================================
RCS file: /sources/hurd/gnumach/device/Attic/blkio.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 blkio.c
--- device/blkio.c 25 Feb 1997 21:28:13 -0000 1.1.1.1
+++ device/blkio.c 28 Aug 2007 11:24:38 -0000
@@ -36,7 +36,9 @@
#include <device/io_req.h>
#include <device/ds_routines.h>
-
+#ifdef MACH_ENTROPY
+#include <device/entropy.h>
+#endif
io_return_t block_io(strat, max_count, ior)
void (*strat)();
@@ -149,6 +151,10 @@
do {
prev = next;
next = prev->io_next;
+#ifdef MACH_ENTROPY
+ /* Let's grab the cylinder numbers for entropy. */
+ entropy_putdata (ior, sizeof(ior), ENTROPY_HIGH_QUALITY, ENTROPY_HIGH_PARANOIA);
+#endif
} while (next != 0 && prev->io_cylinder == next->io_cylinder);
if (next == 0) {
Index: device/cons.c
===================================================================
RCS file: /sources/hurd/gnumach/device/Attic/cons.c,v
retrieving revision 1.2.4.6
diff -u -r1.2.4.6 cons.c
--- device/cons.c 13 Nov 2006 21:30:36 -0000 1.2.4.6
+++ device/cons.c 28 Aug 2007 11:24:38 -0000
@@ -44,6 +44,10 @@
#include <device/kmsg.h>
#endif
+#ifdef MACH_ENTROPY
+#include <device/entropy.h>
+#endif
+
static int cn_inited = 0;
static struct consdev *cn_tab = 0; /* physical console device info */
#ifndef MACH_KERNEL
@@ -230,16 +234,28 @@
cngetc()
{
if (cn_tab)
- return ((*cn_tab->cn_getc)(cn_tab->cn_dev, 1));
- if (romgetc)
- return ((*romgetc)(1));
+ {
+ int c = ((*cn_tab->cn_getc)(cn_tab->cn_dev, 1));
+#if defined(MACH_KERNEL) && defined(MACH_ENTROPY)
+ entropy_putchar (c, ENTROPY_MEDIUM_QUALITY, ENTROPY_MEDIUM_PARANOIA);
+#endif /* MACH_ENTROPY and MACH_ENTROPY */
+ return c;
+ }
+ if (romgetc)
+ {
+ int c = ((*romgetc)(1));
+#if defined (MACH_KERNEL) && defined(MACH_ENTROPY)
+ entropy_putchar(c, ENTROPY_MEDIUM_QUALITY, ENTROPY_MEDIUM_PARANOIA);
+#endif /* MACH_KERNEL && MACH_ENTROPY */
+ return c;
+ }
return (0);
}
#ifdef MACH_KERNEL
int
cnmaygetc()
-{
+ {
if (cn_tab)
return((*cn_tab->cn_getc)(cn_tab->cn_dev, 0));
if (romgetc)
@@ -259,7 +275,12 @@
/* XXX: Assume that All output routines always use cnputc. */
kmsg_putchar (c);
#endif
-
+
+#ifdef MACH_ENTROPY
+ /* Grab character for entropy */
+ entropy_putchar (c, ENTROPY_MEDIUM_QUALITY, ENTROPY_MEDIUM_PARANOIA);
+#endif
+
if (cn_tab) {
(*cn_tab->cn_putc)(cn_tab->cn_dev, c);
if (c == '\n')
Index: i386/i386at/conf.c
===================================================================
RCS file: /sources/hurd/gnumach/i386/i386at/Attic/conf.c,v
retrieving revision 1.4.2.15
diff -u -r1.4.2.15 conf.c
--- i386/i386at/conf.c 1 Apr 2007 22:10:40 -0000 1.4.2.15
+++ i386/i386at/conf.c 28 Aug 2007 11:24:38 -0000
@@ -61,6 +61,11 @@
extern int kmsgopen(), kmsgclose(), kmsgread(), kmsggetstat();
#define kmsgname "kmsg"
+#ifdef MACH_ENTROPY
+#define entropyname "entropy"
+extern int entropyopen(), entropyclose(), entropyread(), entropygetstat();
+#endif
+
/*
* List of devices - console must be at slot 0
*/
@@ -120,6 +125,12 @@
nodev },
#endif
+#ifdef MACH_ENTROPY
+ { entropyname, entropyopen, entropyclose, entropyread,
+ nodev, entropygetstat, nodev, nomap,
+ nodev, nulldev, nulldev, 0,
+ nodev },
+#endif
};
int dev_name_count = sizeof(dev_name_list)/sizeof(dev_name_list[0]);
Index: i386/i386at/kd.c
===================================================================
RCS file: /sources/hurd/gnumach/i386/i386at/Attic/kd.c,v
retrieving revision 1.5.2.13
diff -u -r1.5.2.13 kd.c
--- i386/i386at/kd.c 7 May 2007 22:04:53 -0000 1.5.2.13
+++ i386/i386at/kd.c 28 Aug 2007 11:24:39 -0000
@@ -85,6 +85,11 @@
#include <device/io_req.h>
#include <device/buf.h> /* for struct uio (!) */
#include <vm/vm_kern.h>
+
+#if defined (MACH_KERNEL) && defined(MACH_ENTROPY)
+#include <device/entropy.h>
+#endif /* MACH_KERNEL and MACH _ENTROPY */
+
#include <i386/vm_param.h>
#include <i386/machspl.h>
#include <i386/pio.h>
@@ -811,6 +816,15 @@
up = TRUE;
scancode &= ~K_UP;
}
+
+#if defined(MACH_KERNEL) && defined(MACH_ENTROPY)
+ /* Sune Kirkeby's entropy patch (which was a port of the
+ linux entropy drivers for GNU mach) placed the keyboard
+ entropy source here. I looked at that for an idea of where
+ how to do write this driver. */
+ entropy_putchar(scancode | (up ? 0200 : 0), ENTROPY_MEDIUM_QUALITY, ENTROPY_MEDIUM_PARANOIA);
+ entropy_put_timestamp(ENTROPY_HIGH_QUALITY, ENTROPY_MEDIUM_PARANOIA);
+#endif /* MACH_ENTROPY && MACH_KERNEL */
if (scancode < NUMKEYS) {
/* Lookup in map, then process. */
char_idx = kdstate2idx(kd_state, kd_extended);
Index: i386/i386at/kd_mouse.c
===================================================================
RCS file: /sources/hurd/gnumach/i386/i386at/Attic/kd_mouse.c,v
retrieving revision 1.3.2.8
diff -u -r1.3.2.8 kd_mouse.c
--- i386/i386at/kd_mouse.c 13 Nov 2006 21:30:36 -0000 1.3.2.8
+++ i386/i386at/kd_mouse.c 28 Aug 2007 11:24:39 -0000
@@ -70,6 +70,9 @@
#ifdef MACH_KERNEL
#include <device/errno.h>
#include <device/io_req.h>
+#ifdef MACH_ENTROPY
+#include <device/entropy.h>
+#endif /* MACH_ENTROPY */
#else /* MACH_KERNEL */
#include <sys/file.h>
#include <sys/errno.h>
@@ -677,6 +680,13 @@
moved.mm_deltaX = (char)mousebuf[1] + (char)mousebuf[3];
moved.mm_deltaY = (char)mousebuf[2] + (char)mousebuf[4];
+#ifdef MACH_ENTROPY
+ /* Kick some mouse data to the entropy driver. */
+ entropy_putchar((buttonchanges + moved.mm_deltaX
+ + moved.mm_deltaY), ENTROPY_HIGH_QUALITY, ENTROPY_MEDIUM_PARANOIA);
+ /* And now the time the entropy was added */
+ entropy_put_timestamp(ENTROPY_HIGH_QUALITY, ENTROPY_MEDIUM_PARANOIA);
+#endif
if (moved.mm_deltaX != 0 || moved.mm_deltaY != 0)
mouse_moved(moved);
Index: linux/configfrag.ac
===================================================================
RCS file: /sources/hurd/gnumach/linux/Attic/configfrag.ac,v
retrieving revision 1.1.2.6
diff -u -r1.1.2.6 configfrag.ac
--- linux/configfrag.ac 4 Aug 2007 18:50:19 -0000 1.1.2.6
+++ linux/configfrag.ac 28 Aug 2007 11:24:40 -0000
@@ -605,6 +605,15 @@
[else] AM_CONDITIONAL([CODE_linux], [false])
[fi]
+AC_ARG_ENABLE([entropy],
+ AS_HELP_STRING([--disable-entropy], [disable use of entropy device]))
+ [if [ x"$enable_entropy" != xno ]; then]
+ AC_DEFINE([MACH_ENTROPY], [], [enable use of entropy device])
+ AM_CONDITIONAL([enable_entropy], [true])
+ [else]
+ AM_CONDITIONAL([enable_entropy], [false])
+[fi]
+
dnl Local Variables:
dnl mode: autoconf
dnl End:
Index: linux/dev/glue/misc.c
===================================================================
RCS file: /sources/hurd/gnumach/linux/dev/glue/Attic/misc.c,v
retrieving revision 1.2
diff -u -r1.2 misc.c
--- linux/dev/glue/misc.c 18 Sep 2001 21:14:19 -0000 1.2
+++ linux/dev/glue/misc.c 28 Aug 2007 11:24:41 -0000
@@ -67,6 +67,10 @@
#include <linux/proc_fs.h>
#include <linux/kernel_stat.h>
+#ifdef MACH_ENTROPY
+#include <device/entropy.h>
+#endif
+
extern boolean_t vm_map_lookup_entry (register vm_map_t, register vm_offset_t,
vm_map_entry_t *);
extern int printf (const char *, ...);
@@ -224,6 +228,16 @@
void
add_blkdev_randomness (int major)
{
+#ifdef MACH_ENTROPY
+ /* This is useless for good quality, so we'll only use if it nothing
+ else is available - The problem is that mach only has 1 block
+ device, floppy (major 3 corresponds to Ctrl C) so this is useless
+ for entropic sources. If we ever get more block devices the
+ quality should be upped for additional entropy. */
+
+ entropy_putchar (major, ENTROPY_POOR_QUALITY, ENTROPY_HIGH_PARANOIA);
+ entropy_put_timestamp (ENTROPY_HIGH_QUALITY, ENTROPY_HIGH_PARANOIA);
+#endif
}
void
Index: linux/dev/glue/net.c
===================================================================
RCS file: /sources/hurd/gnumach/linux/dev/glue/Attic/net.c,v
retrieving revision 1.1.4.7
diff -u -r1.1.4.7 net.c
--- linux/dev/glue/net.c 27 Mar 2007 22:47:11 -0000 1.1.4.7
+++ linux/dev/glue/net.c 28 Aug 2007 11:24:41 -0000
@@ -97,6 +97,9 @@
#include <linux/etherdevice.h>
#include <linux/wireless.h>
+#if defined(MACH_KERNEL) && defined(MACH_ENTROPY)
+#include <device/entropy.h>
+#endif /* MACH_KERNEL && MACH_ENTROPY */
extern int linux_intr_pri;
/* One of these is associated with each instance of a device. */
@@ -299,6 +302,12 @@
ph->length = (skb->len - sizeof (struct ether_header)
+ sizeof (struct packet_header));
+#ifdef MACH_ENTROPY
+ /* Grab the packet for entropy purposes. */
+ entropy_putdata(ph + 1, skb->len - sizeof(struct ether_header), ENTROPY_HIGH_QUALITY, ENTROPY_LOW_PARANOIA);
+ entropy_put_timestamp(ENTROPY_HIGH_QUALITY, ENTROPY_LOW_PARANOIA);
+#endif
+
dev_kfree_skb (skb, FREE_READ);
net_kmsg(kmsg)->sent = FALSE; /* Mark packet as received. */
@@ -479,6 +488,12 @@
skb->reply = reply_port;
skb->reply_type = reply_port_type;
+#ifdef MACH_ENTROPY
+ /* Grab the packet for entropy purposes. */
+ entropy_putdata(skb, sizeof(skb), ENTROPY_HIGH_QUALITY, ENTROPY_LOW_PARANOIA);
+ entropy_put_timestamp(ENTROPY_HIGH_QUALITY, ENTROPY_LOW_PARANOIA);
+#endif
+
/* Queue packet for transmission and schedule a software interrupt. */
s = splimp ();
if (dev->buffs[0].next != (struct sk_buff *) &dev->buffs[0]
Index: linux/dev/include/linux/blk.h
===================================================================
RCS file: /sources/hurd/gnumach/linux/dev/include/linux/Attic/blk.h,v
retrieving revision 1.2
diff -u -r1.2 blk.h
--- linux/dev/include/linux/blk.h 5 Apr 2001 06:39:21 -0000 1.2
+++ linux/dev/include/linux/blk.h 28 Aug 2007 11:24:41 -0000
@@ -90,7 +90,7 @@
#endif /* CONFIG_BLK_DEV_MD */
extern void set_device_ro(kdev_t dev,int flag);
-void add_blkdev_randomness(int major);
+extern void add_blkdev_randomness(int major);
extern int floppy_init(void);
extern void rd_load(void);
@@ -136,7 +136,10 @@
#define DEVICE_NR(device) (MINOR(device))
#define DEVICE_ON(device)
#define DEVICE_OFF(device)
+
+#ifndef MACH_ENTROPY
#define DEVICE_NO_RANDOM
+#endif
#elif (MAJOR_NR == FLOPPY_MAJOR)
--- /dev/null 2007-08-26 01:28:58.000000000 -0400
+++ device/entropy.c 2007-08-28 02:06:19.000000016 -0400
@@ -0,0 +1,521 @@
+/*
+ * Mach Kernel - Entropy Generating Device
+ * Copyright (C) 2007 Michael Casadevall
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* System Header Files */
+#include <string.h>
+#include <kern/mach_clock.h>
+
+/* Local Header Files */
+#include "entropy.h"
+
+/* Variable Declarations */
+
+/* Entropy Buffer */
+static char entropy_buffer[ENTROPYBUFSIZE];
+
+/* Lock to each function */
+decl_simple_lock_data(static,entropy_lock);
+
+/* Current read offset */
+static int entropy_read_offset = 0;
+
+/* Current write offset */
+static int entropy_write_offset = 0;
+
+/* Current amount of entropy */
+static int entropy_amount = 0;
+
+/* If this device is already initalized */
+static int entropy_init_done = 0;
+
+/* I/O queue requests for blocking read */
+static queue_head_t entropy_read_queue;
+
+/* Entropy Pool Empty? */
+static int is_entropy_empty = 1;
+
+/* Generate/Use Entropic Average Quality */
+static int use_entropic_average = 0;
+
+/* Entropic Quality */
+static int entropy_qualities[ENTROPYBUFSIZE];
+
+/* Current Entropic Quality (scale of 0-10) */
+static int entropy_average = 0;
+
+/*
+ * The following is from linux's random.c, and is used
+ * under the GPL.
+ *
+ * Look there for a full explination on what these numbers
+ * mean and how this works.
+ */
+
+static struct poolinfo {
+ int poolwords;
+ int tap1, tap2, tap3, tap4, tap5;
+ } poolinfo_table [] = {
+ /* x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 -- 105 */
+ { 128, 103, 76, 51, 25, 1 },
+ /* x^32 + x^26 + x^20 + x^14 + x^7 + x + 1 -- 15 */
+ { 32, 26, 20, 14, 7, 1 },
+ /* x^2048 + x^1638 + x^1231 + x^819 + x^411 + x + 1 -- 115 */
+ { 2048, 1638, 1231, 819, 411, 1 },
+ /* x^1024 + x^817 + x^615 + x^412 + x^204 + x + 1 -- 290 */
+ { 1024, 817, 615, 412, 204, 1 },
+ /* x^1024 + x^819 + x^616 + x^410 + x^207 + x^2 + 1 -- 115 */
+ { 1024, 819, 616, 410, 207, 2 },
+ /* x^512 + x^411 + x^308 + x^208 + x^104 + x + 1 -- 225 */
+ { 512, 411, 308, 208, 104, 1 },
+ /* x^512 + x^409 + x^307 + x^206 + x^102 + x^2 + 1 -- 95 */
+ { 512, 409, 307, 206, 102, 2 },
+ /* x^512 + x^409 + x^309 + x^205 + x^103 + x^2 + 1 -- 95 */
+ { 512, 409, 309, 205, 103, 2 },
+ /* x^256 + x^205 + x^155 + x^101 + x^52 + x + 1 -- 125 */
+ { 256, 205, 155, 101, 52, 1 },
+ /* x^128 + x^103 + x^78 + x^51 + x^27 + x^2 + 1 -- 70 */
+ { 128, 103, 78, 51, 27, 2 },
+ /* x^64 + x^52 + x^39 + x^26 + x^14 + x + 1 -- 15 */
+ { 64, 52, 39, 26, 14, 1 },
+};
+
+/* Number of taps -1 */
+const int number_of_taps = 10;
+
+void
+entropyinit()
+{
+ /* Sanity check! */
+ if (entropy_init_done == 1) {
+ assert(entropy_init_done);
+ }
+
+ /* Zero out array's */
+ memset(entropy_qualities, 0, ENTROPYBUFSIZE);
+ memset(entropy_buffer, 0, ENTROPYBUFSIZE);
+
+ /* Setup locks */
+ queue_init(&entropy_read_queue);
+ simple_lock_init(&entropy_lock);
+ entropy_init_done = 1;
+}
+
+io_return_t
+entropyopen(dev_t dev, int flag, io_req_t ior)
+{
+ /* Check to see if we've initalized entropy. */
+ if (entropy_init_done == 0)
+ {
+ entropyinit();
+ }
+
+ /* Lock the function so we don't get a race condition. */
+ simple_lock(&entropy_lock);
+
+ /* We're done, unlock, and return success. */
+ simple_unlock(&entropy_lock);
+ return D_SUCCESS;
+}
+
+io_return_t
+entropyclose(dev_t dev, int flag)
+{
+ return D_SUCCESS;
+}
+
+/* Forward Declaration */
+static boolean_t entropy_read_done(io_req_t ior);
+
+io_return_t
+entropyread(dev_t dev, io_req_t ior)
+{
+ /* Possible error code. */
+ int err;
+
+ /* Amount of entropy we want to read out. */
+ int amt;
+
+ /* Amount of entropy we have to read out. */
+ int len;
+
+ /* Allocate memory. */
+ err = device_read_alloc(ior, ior->io_count);
+ if (err != KERN_SUCCESS)
+ {
+ return err;
+ }
+
+ /* Lock the device. */
+ simple_lock(&entropy_lock);
+ if (is_entropy_empty == 1)
+ {
+
+ /* We got no entropy at the moment, queue it up. */
+ if (ior->io_mode & D_NOWAIT) {
+ /* Got a non-blocking socket, so just tell it we would
+ block. */
+ simple_unlock(&entropy_lock);
+ return D_WOULD_BLOCK;
+ }
+
+ /* Pass the point to the read_done function which will notify if
+ the IO read is REALLY done. */
+
+ ior->io_done = entropy_read_done;
+
+ /* queue it up. */
+ enqueue_tail(&entropy_read_queue, (queue_entry_t) ior);
+ simple_unlock(&entropy_lock);
+ return D_IO_QUEUED;
+ }
+
+ /* Determine how much we're reading out. */
+ len = entropy_write_offset - entropy_read_offset;
+
+ if (len < 0 )
+ len += ENTROPYBUFSIZE;
+
+ amt = ior->io_count;
+ if (amt > len)
+ {
+ /* This read will deplete the pool, mark it empty */
+ amt = len;
+ is_entropy_empty = 1;
+ }
+
+ if (entropy_read_offset + amt <= ENTROPYBUFSIZE)
+ {
+ /* Copy available entropy into the device buffer. */
+ memcpy (ior->io_data, entropy_buffer + entropy_read_offset, amt);
+ }
+ else
+ {
+ /* We need to wrap around so do it in two copies. */
+ int cnt;
+ cnt = ENTROPYBUFSIZE - entropy_read_offset;
+ memcpy(ior->io_data, entropy_buffer + entropy_read_offset, cnt);
+ memcpy(ior->io_data, entropy_buffer, amt - cnt);
+ }
+
+ /* Move the read offset. */
+ entropy_read_offset += amt;
+ if (entropy_read_offset >= ENTROPYBUFSIZE) {
+ entropy_read_offset -= ENTROPYBUFSIZE;
+ }
+
+ /* Notify the caller how much data we were able to return. */
+ ior->io_residual = ior->io_count - amt;
+
+ /* Update the amount of entropy in the buffer */
+ entropy_amount =- amt;
+
+ /* Since the buffer is no longer full, stop generating averages
+ until its refilled */
+ use_entropic_average = 0;
+
+ /* Unlock, and return success. */
+ simple_unlock(&entropy_lock);
+ return D_SUCCESS;
+}
+
+/* This function called when the io read is complete by
+ device_read. */
+static boolean_t
+entropy_read_done(io_req_t ior)
+{
+ /* Amount of entropy we want. */
+ int amt;
+
+ /* Amount of entropy we have. */
+ int len;
+
+ /* Lock the device. */
+ simple_lock(&entropy_lock);
+ if (is_entropy_empty == 1)
+ {
+ /* The queue is empty so return false. */
+ ior->io_done = entropy_read_done;
+ enqueue_tail(&entropy_read_queue, (queue_entry_t) ior);
+ simple_unlock (&entropy_lock);
+ return FALSE;
+ }
+
+ len = entropy_write_offset - entropy_read_offset;
+ if (len < 0)
+ len += ENTROPYBUFSIZE;
+
+ amt = ior->io_count;
+ if (amt > len)
+ {
+ /* This read will depelete the pool, mark it empty */
+ is_entropy_empty = 1;
+ amt = len;
+ }
+
+ if (entropy_read_offset + amt <= ENTROPYBUFSIZE)
+ {
+ /* Copy the data from the buffer. */
+ memcpy (ior->io_data, entropy_buffer + entropy_read_offset, amt);
+ }
+ else
+ {
+ /* The buffer needs to wrap around, so copy in two
+ installments. */
+ int cnt;
+
+ cnt = ENTROPYBUFSIZE - entropy_read_offset;
+ memcpy (ior->io_data, entropy_buffer + entropy_read_offset, cnt);
+ memcpy (ior->io_data + cnt, entropy_buffer, amt - cnt);
+ }
+
+
+ entropy_read_offset += amt;
+ if (entropy_read_offset >= ENTROPYBUFSIZE)
+ {
+ entropy_read_offset -= ENTROPYBUFSIZE;
+ }
+
+ /* Notify the caller the amount of entropy returned
+ and update the buffer count */
+ ior->io_residual = ior->io_count - amt;
+ entropy_amount =- amt;
+
+ /* The entropy buffer is no longer full, stop generating averages */
+ use_entropic_average = 0;
+
+ /* Finish up, and unlock */
+ simple_unlock(&entropy_lock);
+ ds_read_done (ior);
+
+ return TRUE;
+}
+
+io_return_t
+entropygetstat(dev_t dev, int flavor, int *data, unsigned int *count)
+{
+ switch (flavor)
+ {
+ case DEV_GET_SIZE:
+ data[DEV_GET_SIZE_DEVICE_SIZE] = 0;
+ data[DEV_GET_SIZE_RECORD_SIZE] = 1;
+ *count = DEV_GET_SIZE_COUNT;
+ break;
+ default:
+ return D_INVALID_OPERATION;
+ }
+
+ return D_SUCCESS;
+}
+
+void
+entropy_putchar(char c, enum entropy_quality quality, enum entropy_paranoia paranoia)
+{
+ /* We'll get data from a given source, and stick it in the
+ buffer. */
+ io_req_t ior;
+
+
+ /* Do we trust the entropy coming in? */
+ if (ENTROPY_PARANOIA_LEVEL > quality)
+ return;
+
+ /* Its possible we MIGHT get here before the device is opened so
+ just make sure we're initalized before doing anything! */
+
+ if(!entropy_init_done)
+ entropyinit();
+
+ /* Ok, we're going to TRY to lock since we don't want to block trying
+ to get the lock. */
+
+ if (!simple_lock_try(&entropy_lock))
+ /* Didn't get it, bail out. */
+ return;
+
+
+ /* Alright, we can do one of three things
+ 1. Uncondtionally accept incoming entropy
+ (done if the buffer is not full)
+ 2. Conditionally accept
+ 3. Reject */
+
+ /* See if we're currently calculating averages. If so, will the
+ incoming entropy improve the average? */
+ if (use_entropic_average == 1)
+ {
+
+ /* We subtract by 1 because if we don't, the buffer will end up
+ filled only by sources with the highest entropic quality; I'm
+ 100% sure this is the proper behavior, so any improvements
+ would be most appericated */
+
+ if ((entropy_average - 1) >= quality)
+ return;
+ }
+
+ /* Ok, are we unconditionally adding the entropy,
+ or do we need to seek low entropy, and replace
+ it with high entropy? */
+ if (use_entropic_average == 1)
+ {
+ int i = 0;
+ /* Lets walk the buffer until we find poor entropy, and replace
+ it with good entropy */
+ for (i = 0; i != ENTROPYBUFSIZE; i++)
+ {
+ if (quality > entropy_qualities[i])
+ {
+ entropy_qualities[i] = quality;
+ entropy_buffer[i] = entropy_twist_char(c);
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* Unconditionally add */
+ /* Add the entropy and its quality to the buffer. */
+ entropy_buffer[entropy_write_offset] = entropy_twist_char(c);
+ entropy_qualities[entropy_write_offset] = quality;
+
+ /* Advance the pointer for the next write. */
+ entropy_write_offset += 1;
+
+ if (entropy_write_offset == ENTROPYBUFSIZE)
+ entropy_write_offset = 0;
+
+ /* If the buffer been filled, start generating averages */
+ if (entropy_amount == ENTROPYBUFSIZE)
+ use_entropic_average = 1;
+ else
+ entropy_amount++;
+ }
+
+ /* Lets generate the averages */
+ if (use_entropic_average == 1 )
+ {
+ int total = 0;
+ int i = 0;
+
+ for (i = 0; i != ENTROPYBUFSIZE; i++)
+ total = total + entropy_qualities[i];
+
+ /* And now that we have the total, get the average */
+ entropy_average = total/ENTROPYBUFSIZE;
+ }
+
+ /* And make it that the buffer is no longer empty */
+ is_entropy_empty = 0;
+
+ /* Deep magic (tells any read functions more entropy is
+ available) */
+
+ while ((ior = (io_req_t) dequeue_head (&entropy_read_queue)) != NULL)
+ iodone (ior);
+
+ simple_unlock(&entropy_lock);
+}
+
+/* This function is used to copy data from memory pointers directly
+ into the bufffer */
+
+void
+entropy_putdata (char *data, int size, enum entropy_quality quality, enum entropy_paranoia paranoia)
+{
+ /* Loop counter */
+ int i;
+
+ /* Do we trust the entropy coming in? */
+ if (ENTROPY_PARANOIA_LEVEL > paranoia)
+ return;
+
+ /* See if we are initalized; if not, initalize the driver. */
+ if (!entropy_init_done)
+ entropyinit();
+
+ /* Is the data we're copying in bigger then our buffer? */
+ if (size >= ENTROPYBUFSIZE)
+ {
+ /* Set the offset to zero, and then copy set the size to the
+ size of the buffer. */
+
+ size = ENTROPYBUFSIZE;
+ }
+
+ /* entropy_putchar is going to handle twisting, so simply feed into
+ it bit by bit. */
+ for (i = 0; i == size; i++)
+ entropy_putchar(data[i], quality, paranoia);
+}
+
+void
+entropy_put_timestamp(enum entropy_quality quality, enum entropy_paranoia paranoia)
+{
+ /* elasped ticks is a global from mach_clock.h */
+ entropy_putchar(elapsed_ticks, quality, paranoia);
+}
+
+
+/* This function twists the incoming char,
+ and returns the twisted char */
+
+char
+entropy_twist_char(char c)
+{
+ /* Twist table, and twisting and mixing code adopted from Linux's
+ random.c. */
+ static unsigned long const twist_table [8] = {
+ 0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
+ 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 };
+ /* Taps available for use. */
+ unsigned long int tap1, tap2, tap3, tap4, tap5;
+
+ /* Random mask to twist by. */
+ int wordmask;
+
+ /* Bit rotation of the taps. */
+ static int input_rotate;
+
+ /* Current Tap in use. */
+ static short current_tap;
+
+ /* Input being twisted. */
+ unsigned long word;
+
+ /* Get the taps based on which array to use. */
+ wordmask = poolinfo_table[current_tap].poolwords - 1;
+ tap1 = poolinfo_table[current_tap].tap1;
+ tap2 = poolinfo_table[current_tap].tap2;
+ tap3 = poolinfo_table[current_tap].tap3;
+ tap4 = poolinfo_table[current_tap].tap4;
+ tap5 = poolinfo_table[current_tap].tap5;
+
+ /* Mix the tap into the incoming entropy. */
+ c++;
+ word = ((c << input_rotate) | (c >> (32 - input_rotate)));
+
+ /* XOR in the various taps, then add to the buffer. */
+ word ^= entropy_buffer[(entropy_write_offset + tap1) & wordmask];
+ word ^= entropy_buffer[(entropy_write_offset + tap2) & wordmask];
+ word ^= entropy_buffer[(entropy_write_offset + tap3) & wordmask];
+ word ^= entropy_buffer[(entropy_write_offset + tap4) & wordmask];
+ word ^= entropy_buffer[(entropy_write_offset + tap5) & wordmask];
+
+ return ((word >> 3) ^ twist_table[word & 7]);
+}
--- /dev/null 2007-08-26 01:28:58.000000000 -0400
+++ device/entropy.h 2007-08-27 22:20:41.000000000 -0400
@@ -0,0 +1,77 @@
+/*
+ * Mach Kernel - Entropy Generating Device
+ * Copyright (C) 2007 Michael Casadevall
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Entropy device header. */
+
+#ifndef _DEVICE_ENTROPY_H_
+#define _DEVICE_ENTROPY_H_
+
+#ifdef MACH_KERNEL
+
+#include <sys/types.h>
+#include <device/conf.h>
+#include <device/ds_routines.h>
+#include <device/io_req.h>
+#include <device/device_types.h>
+
+#define ENTROPYBUFSIZE (sizeof(char)*512)
+
+/* configure should give us a paranoia level
+ but if not, we'll default to none */
+
+/* FIXME: Make this changable at runtime */
+#ifndef ENTROPY_PARANOIA_LEVEL
+#define ENTROPY_PARANOIA_LEVEL 0
+#endif /* ENTROPY_PARANOIA_LEVEL */
+
+/* Entropy qualities */
+enum entropy_quality
+ {
+ ENTROPY_POOR_QUALITY = 2,
+ ENTROPY_LOW_QUALITY = 4,
+ ENTROPY_MEDIUM_QUALITY = 6,
+ ENTROPY_HIGH_QUALITY = 8,
+ ENTROPY_PERFECT_QUALITY = 10
+ };
+
+/* Paranoia (defines how much a source is trusted; higher is
+ better.) */
+enum entropy_paranoia
+ {
+ ENTROPY_NO_PARANOIA = 0,
+ ENTROPY_LOW_PARANOIA = 1,
+ ENTROPY_MEDIUM_PARANOIA = 2,
+ ENTROPY_HIGH_PARANOIA = 3,
+ ENTROPY_PARANOID_PARNOIA = 4
+ };
+
+
+io_return_t entropyopen(dev_t dev, int flag, io_req_t ior);
+io_return_t entropyclose(dev_t dev, int flag);
+io_return_t entropyread(dev_t dev, io_req_t ior);
+io_return_t entropygetstat(dev_t dev, int flavor,
+ int *data, unsigned int *count);
+void entropy_putchar(char c, enum entropy_quality quality, enum entropy_paranoia paranoia);
+void entropy_putdata(char *data, int size, enum entropy_quality quality, enum entropy_paranoia paranoia);
+void entropy_put_timestamp(enum entropy_quality quality, enum entropy_paranoia paranoia);
+
+char entropy_twist_char(char c);
+
+#endif /* MACH_KERNEL */
+#endif /* ! _DEVICE_ENTROPY_H_ */
_______________________________________________
Bug-hurd mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/bug-hurd