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
Bug-hurd@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-hurd

Reply via email to