-/* $OpenBSD: rnd.c,v 1.7 1996/08/29 09:26:36 deraadt Exp $ */
+/* $OpenBSD: rnd.c,v 1.8 1996/09/06 08:36:13 mickey Exp $ */
/*
- * Copyright (c) 1996 Michael Shalayeff.
- *
- * This software derived from one contributed by Theodore Ts'o.
- *
- * 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.
- * 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Theodore Ts'o.
- * 4. Neither the name of the University nor of the Laboratory may be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
- *
- *
- *
* random.c -- A strong random number generator
*
- * Version 0.96, last modified 29-Dec-95
+ * Copyright (c) 1996 Michael Shalayeff.
+ *
+ * Version 1.00, last modified 26-May-96
*
- * Copyright Theodore Ts'o, 1994, 1995. All rights reserved.
+ * Copyright Theodore Ts'o, 1994, 1995, 1996. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* and returns good random numbers, suitable for cryptographic use.
* Besides the obvious cryptographic uses, these numbers are also good
* for seeding TCP sequence numbers, and other places where it is
- * desireable to have numbers which are not only random, but hard to
+ * desirable to have numbers which are not only random, but hard to
* predict by an attacker.
*
* Theory of operation
* ===================
*
* Computers are very predictable devices. Hence it is extremely hard
- * to produce truely random numbers on a computer --- as opposed to
+ * to produce truly random numbers on a computer --- as opposed to
* pseudo-random numbers, which can easily generated by using a
* algorithm. Unfortunately, it is very easy for attackers to guess
* the sequence of pseudo-random number generators, and for some
* random numbers; however, an attacker may (at least in theory) be
* able to infer the future output of the generator from prior
* outputs. This requires successful cryptanalysis of MD5, which is
- * not believed to be feasible, but there is a remote possiblility.
+ * not believed to be feasible, but there is a remote possibility.
* Nonetheless, these numbers should be useful for the vast majority
* of purposes.
*
* The current exported interfaces for gathering environmental noise
* from the devices are:
*
- * void add_keyboard_randomness(u_char scancode);
* void add_mouse_randomness(u_int32_t mouse_data);
- * void add_interrupt_randomness(int irq);
- * void add_blkdev_randomness(dev_t dev);
+ * void add_net_randomness(int isr);
+ * void add_tty_randomness(dev_t dev, int c);
+ * void add_blkdev_randomness(int irq);
*
* add_keyboard_randomness() uses the inter-keypress timing, as well as the
* scancode as random inputs into the "entropy pool".
* particular randomness source. They do this by keeping track of the
* first and second order deltas of the event timings.
*
+ * Ensuring unpredictability at system startup
+ * ============================================
+ *
+ * When any operating system starts up, it will go through a sequence
+ * of actions that are fairly predictable by an adversary, especially
+ * if the start-up does not involve interaction with a human operator.
+ * This reduces the actual number of bits of unpredictability in the
+ * entropy pool below the value in entropy_count. In order to
+ * counteract this effect, it helps to carry information in the
+ * entropy pool across shut-downs and start-ups. To do this, put the
+ * following lines an appropriate script which is run during the boot
+ * sequence:
+ *
+ * echo "Initializing random number generator..."
+ * # Carry a random seed from start-up to start-up
+ * # Load and then save 512 bytes, which is the size of the entropy pool
+ * if [ -f /etc/random-seed ]; then
+ * cat /etc/random-seed >/dev/urandom
+ * fi
+ * dd if=/dev/urandom of=/etc/random-seed count=1
+ *
+ * and the following lines in an appropriate script which is run as
+ * the system is shutdown:
+ *
+ * # Carry a random seed from shut-down to start-up
+ * # Save 512 bytes, which is the size of the entropy pool
+ * echo "Saving random seed..."
+ * dd if=/dev/urandom of=/etc/random-seed count=1
+ *
+ * For example, on many Linux systems, the appropriate scripts are
+ * usually /etc/rc.d/rc.local and /etc/rc.d/rc.0, respectively.
+ *
+ * Effectively, these commands cause the contents of the entropy pool
+ * to be saved at shut-down time and reloaded into the entropy pool at
+ * start-up. (The 'dd' in the addition to the bootup script is to
+ * make sure that /etc/random-seed is different for every start-up,
+ * even if the system crashes without executing rc.0.) Even with
+ * complete knowledge of the start-up activities, predicting the state
+ * of the entropy pool requires knowledge of the previous history of
+ * the system.
+ *
+ * Configuring the /dev/random driver under Linux
+ * ==============================================
+ *
+ * The /dev/random driver under Linux uses minor numbers 8 and 9 of
+ * the /dev/mem major number (#1). So if your system does not have
+ * /dev/random and /dev/urandom created already, they can be created
+ * by using the commands:
+ *
+ * mknod /dev/random c 1 8
+ * mknod /dev/urandom c 1 9
+ *
* Acknowledgements:
* =================
*
* entropy pool, taken from PGP 3.0 (under development). It has since
* been modified by myself to provide better mixing in the case where
* the input values to add_entropy_word() are mostly small numbers.
+ * Dale Worley has also contributed many useful ideas and suggestions
+ * to improve this driver.
*
* Any flaws in the design are solely my responsibility, and should
* not be attributed to the Phil, Colin, or any of authors of PGP.
*
+ * The code for MD5 transform was taken from Colin Plumb's
+ * implementation, which has been placed in the public domain. The
+ * MD5 cryptographic checksum was devised by Ronald Rivest, and is
+ * documented in RFC 1321, "The MD5 Message Digest Algorithm".
+ *
+ * Further background information on this topic may be obtained from
+ * RFC 1750, "Randomness Recommendations for Security", by Donald
+ * Eastlake, Steve Crocker, and Jeff Schiller.
*/
#include "random.h"
#define RD_WAIT 0x0100 /* sleep/wakeup for good data */
#endif
+#ifdef RND_USE_SHA
+#define HASH_BUFFER_SIZE 5
+#define HASH_TRANSFORM SHATransform
+#else /* RND_USE_MD5 */
+#ifndef RND_USE_MD5
+#define RND_USE_MD5
+#endif
+#define HASH_BUFFER_SIZE 4
+#define HASH_TRANSFORM MD5Transform
+#endif
+
/*
* The pool is stirred with a primitive polynomial of degree 128
* over GF(2), namely x^128 + x^99 + x^59 + x^31 + x^9 + x^7 + 1.
#define ENT_BLKDEV 0x200
#define ENT_TTY 0x300
-/* device functions prototypes: XXX move em to dev_conf.h */
-cdev_decl(random);
-
static struct random_bucket random_state;
struct arc4_stream arc4random_state;
static u_int32_t random_pool[POOLWORDS];
return (as->s[(si + sj) & 0xff]);
}
-u_long
+u_int32_t
arc4random (void)
{
return ((arc4_getbyte (&arc4random_state) << 24)
| (arc4_getbyte (&arc4random_state) << 8)
| arc4_getbyte (&arc4random_state));
}
-
+
void
randomattach(num)
int num;
{
int delta, delta2;
u_int nbits;
- u_int32_t time;
+ u_long time;
{
struct timeval tv;
}
}
-void
-add_keyboard_randomness(scancode)
- u_char scancode;
-{
-#ifdef DEBUG
- if (rnd_debug & RD_INPUT)
- printf("rnd: adding %02x from kbd\n", scancode);
-#endif
- add_timer_randomness(&random_state, &keyboard_timer_state, scancode);
-}
-
void
add_mouse_randomness(mouse_data)
u_int32_t mouse_data;
int nbytes;
{
int ret, i;
- u_int32_t tmp[4];
+ u_int32_t tmp[HASH_BUFFER_SIZE];
add_timer_randomness(r, &extract_timer_state, nbytes);
/* Redundant, but just in case... */
if (r->entropy_count > POOLBITS)
r->entropy_count = POOLBITS;
- /* Why is this here? Left in from Ted Ts'o. Perhaps to limit time. */
- if (nbytes > 32768)
- nbytes = 32768;
ret = nbytes;
if (r->entropy_count / 8 >= nbytes)
while (nbytes) {
/* Hash the pool to get the output */
+#ifdef RND_USE_MD5
MD5Init(tmp);
+#endif
for (i = 0; i < POOLWORDS; i += 16)
- MD5Transform(tmp, r->pool+i);
+ HASH_TRANSFORM(tmp, r->pool+i);
/* Modify pool so next hash will produce different results */
add_entropy_word(r, tmp[0]);
add_entropy_word(r, tmp[1]);
add_entropy_word(r, tmp[2]);
add_entropy_word(r, tmp[3]);
+#ifdef RND_USE_SHA
+ add_entropy_word(r, tmp[5]);
+#endif
/*
* Run the MD5 Transform one more time, since we want
* to add at least minimal obscuring of the inputs to
* add_entropy_word(). --- TYT
*/
- MD5Transform(tmp, r->pool);
-
+ HASH_TRANSFORM(tmp, r->pool);
+
+ /*
+ * In case the hash function has some recognizable
+ * output pattern, we fold it in half.
+ */
+ {
+ register u_int8_t *cp, *dp;
+ cp = (u_int8_t *) tmp;
+ dp = cp + (HASH_BUFFER_SIZE*sizeof(tmp[0])) - 1;
+ for (i=0; i < HASH_BUFFER_SIZE*sizeof(tmp[0])/2; i++) {
+ *cp ^= *dp;
+ cp++; dp--;
+ }
+ }
+
/* Copy data to destination buffer */
- i = MIN(nbytes, 16);
+ i = MIN(nbytes, HASH_BUFFER_SIZE*sizeof(tmp[0]));
bcopy((caddr_t)tmp, buf, i);
nbytes -= i;
buf += i;
+ add_timer_randomness(r, &extract_timer_state, nbytes);
}
/* Wipe data from memory */
s = splhigh();
switch(minor(dev)) {
case RND_RND:
+ ret = EIO; /* no chip -- error */
break;
case RND_SRND:
if (random_state.entropy_count < 8) {