-/* $OpenBSD: rnd.c,v 1.33 1999/09/28 01:24:46 deraadt Exp $ */
+/* $OpenBSD: rnd.c,v 1.34 2000/03/19 17:38:03 mickey Exp $ */
/*
* random.c -- A strong random number generator
* Eastlake, Steve Crocker, and Jeff Schiller.
*/
+#undef RNDEBUG
+
#include <sys/param.h>
-#include <sys/types.h>
#include <sys/systm.h>
-#include <sys/kernel.h>
#include <sys/conf.h>
-#include <sys/device.h>
#include <sys/disk.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
-#include <sys/proc.h>
-#include <sys/user.h>
#include <sys/fcntl.h>
#include <sys/vnode.h>
#include <sys/md5k.h>
#include <sys/sysctl.h>
-#include <net/netisr.h>
-
#include <dev/rndvar.h>
#include <dev/rndioctl.h>
-#ifdef DEBUG
+#ifdef RNDEBUG
int rnd_debug = 0x0000;
#define RD_INPUT 0x000f /* input data */
#define RD_OUTPUT 0x00f0 /* output data */
/* p60/256kL2 reported to have some drops w/ these numbers */
#define QEVLEN 40
#define QEVSLOW 32 /* yet another 0.75 for 60-minutes hour /-; */
-#define QEVSBITS 4
+#define QEVSBITS 6
/* There is actually only one of these, globally. */
struct random_bucket {
u_int8_t i;
u_int8_t j;
u_int8_t s[256];
- int cnt;
+ u_int cnt;
};
struct rand_event {
static __inline void add_entropy_word __P((const u_int32_t));
static void enqueue_randomness __P((register struct timer_rand_state*, u_int));
void dequeue_randomness __P((void *));
-static __inline int extract_entropy __P((register u_int8_t *, int));
+static __inline void extract_entropy __P((register u_int8_t *, int));
void arc4_init __P((u_int8_t *, int));
static __inline void arc4_stir __P((void));
static __inline u_int8_t arc4_getbyte __P((void));
}
}
+int
+arc4random_8(void)
+{
+ arc4maybeinit();
+ return arc4_getbyte();
+}
+
u_int32_t
-arc4random (void)
+arc4random(void)
{
arc4maybeinit ();
return ((arc4_getbyte () << 24) | (arc4_getbyte () << 16)
get_random_bytes (buf + sizeof (struct timeval),
sizeof (buf) - sizeof (struct timeval));
arc4_init (buf, sizeof (buf));
+ rndstats.arc4_stirs++;
}
void
struct rand_event *rep;
if (rnd_attached) {
-#ifdef DEBUG
+#ifdef RNDEBUG
printf("random: second attach\n");
#endif
return;
register struct timer_rand_state *state;
u_int val;
{
- u_int nbits = 0;
struct timeval tv;
register struct rand_event *rep;
int s;
- u_int time;
+ u_int time, nbits;
rndstats.rnd_enqs++;
microtime(&tv);
time = tv.tv_usec ^ tv.tv_sec;
+ nbits = 0;
+
/*
* Calculate number of bits of randomness we probably
* added. We take into account the first and second order
if (delta < 0) delta = -delta;
if (delta2 < 0) delta2 = -delta2;
- delta = MIN(delta, delta2) >> 1;
- for (nbits = 0; delta; nbits++)
+ delta2 = delta = MIN(delta, delta2) >> 1;
+
+ if (delta & 0xffff0000) {
+ nbits = 16;
+ delta >>= 16;
+ }
+ if (delta & 0xff00) {
+ nbits += 8;
+ delta >>= 8;
+ }
+ if (delta & 0xf0) {
+ nbits += 4;
+ delta >>= 4;
+ }
+ if (delta & 0xc) {
+ nbits += 2;
+ delta >>= 2;
+ }
+ if (delta & 2) {
+ nbits += 1;
delta >>= 1;
+ }
+ if (delta & 1)
+ nbits++;
- if (rndstats.rnd_queued > QEVSLOW && nbits < QEVSBITS) {
+ rndstats.rnd_ed[nbits]++;
+
+ if (rndstats.rnd_queued > QEVSLOW && nbits > QEVSBITS) {
rndstats.rnd_drople++;
return;
}
state->last_time = time;
- state->last_delta = delta;
+ state->last_delta = delta2;
}
s = splhigh();
rndstats.rnd_queued++;
if (rep == NULL)
- timeout(dequeue_randomness, (void *)0xdeadd00d, 1);
+ timeout(dequeue_randomness, NULL, 1);
}
rndstats.rnd_queued--;
if (random_state.entropy_count > 8 &&
rndstats.rnd_asleep != 0) {
-#ifdef DEBUG
+#ifdef RNDEBUG
if (rnd_debug & RD_WAIT)
printf("rnd: wakeup[%d]{%u}\n",
rndstats.rnd_asleep,
* bits of entropy are left in the pool, but it does not restrict the
* number of bytes that are actually obtained.
*/
-static __inline int
+static __inline void
extract_entropy(buf, nbytes)
register u_int8_t *buf;
int nbytes;
{
- int ret, i;
+ int i;
MD5_CTX tmp;
enqueue_randomness(&extract_timer_state, nbytes);
if (random_state.entropy_count > POOLBITS)
random_state.entropy_count = POOLBITS;
- ret = nbytes;
if (random_state.entropy_count / 8 >= nbytes)
random_state.entropy_count -= nbytes*8;
else
/* Wipe data from memory */
bzero(&tmp, sizeof(tmp));
-
- return ret;
}
/*
ret = EWOULDBLOCK;
break;
}
-#ifdef DEBUG
+#ifdef RNDEBUG
if (rnd_debug & RD_WAIT)
printf("rnd: sleep[%d]\n",
rndstats.rnd_asleep);
rndstats.rnd_waits++;
ret = tsleep(&rndstats.rnd_asleep,
PWAIT | PCATCH, "rndrd", 0);
-#ifdef DEBUG
+#ifdef RNDEBUG
if (rnd_debug & RD_WAIT)
printf("rnd: awakened(%d)\n", ret);
#endif
}
n = min(n, random_state.entropy_count / 8);
rndstats.rnd_reads++;
-#ifdef DEBUG
+#ifdef RNDEBUG
if (rnd_debug & RD_OUTPUT)
printf("rnd: %u possible output\n", n);
#endif
case RND_URND:
- n = extract_entropy((char *)buf, n);
-#ifdef DEBUG
+ get_random_bytes((char *)buf, n);
+#ifdef RNDEBUG
if (rnd_debug & RD_OUTPUT)
printf("rnd: %u bytes for output\n", n);
#endif
{
u_int8_t *cp = (u_int8_t *) buf;
u_int8_t *end = cp + n;
- arc4maybeinit ();
while (cp < end)
- *cp++ = arc4_getbyte ();
+ *cp++ = arc4random_8();
break;
}
}
}
if (minor(dev) == RND_ARND && !ret)
- arc4_stir ();
+ arc4random_uninitialized = 2;
return ret;
}
return EPERM;
if (random_state.entropy_count < 64)
return EAGAIN;
- arc4_stir ();
+ arc4random_uninitialized = 2;
ret = 0;
break;
default:
-/* $OpenBSD: rndvar.h,v 1.11 1997/06/28 07:05:23 deraadt Exp $ */
+/* $OpenBSD: rndvar.h,v 1.12 2000/03/19 17:38:03 mickey Exp $ */
/*
* Copyright (c) 1996 Michael Shalayeff.
#define RND_NODEV 5 /* First invalid minor device number */
struct rndstats {
- u_int32_t rnd_total; /* total bits of entropy generated */
- u_int32_t rnd_used; /* strong data bits read so far */
- u_int32_t arc4_reads;/* aRC4 data bytes read so far */
+ u_long rnd_total; /* total bits of entropy generated */
+ u_long rnd_used; /* strong data bits read so far */
+ u_long arc4_reads;/* aRC4 data bytes read so far */
- u_int32_t rnd_timer; /* timer calls */
- u_int32_t rnd_mouse; /* mouse calls */
- u_int32_t rnd_tty; /* tty calls */
- u_int32_t rnd_disk; /* block devices calls */
- u_int32_t rnd_net; /* net calls */
+ u_long rnd_timer; /* timer calls */
+ u_long rnd_mouse; /* mouse calls */
+ u_long rnd_tty; /* tty calls */
+ u_long rnd_disk; /* block devices calls */
+ u_long rnd_net; /* net calls */
- u_int32_t rnd_reads; /* strong read calls */
- u_int32_t rnd_waits; /* sleep for data */
- u_int32_t rnd_enqs; /* enqueue calls */
- u_int32_t rnd_deqs; /* dequeue calls */
- u_int32_t rnd_drops; /* queue-full drops */
- u_int32_t rnd_drople;/* queue low watermark low entropy drops */
+ u_long rnd_reads; /* strong read calls */
+ u_long rnd_waits; /* sleep for data */
+ u_long rnd_enqs; /* enqueue calls */
+ u_long rnd_deqs; /* dequeue calls */
+ u_long rnd_drops; /* queue-full drops */
+ u_long rnd_drople;/* queue low watermark low entropy drops */
- u_int32_t rnd_asleep; /* sleeping for the data */
- u_int32_t rnd_queued; /* queued for processing */
+ u_long rnd_asleep;/* sleeping for the data */
+ u_long rnd_queued;/* queued for processing */
+ u_long arc4_stirs;/* arc4 pool stirs */
+
+ u_long rnd_ed[32];/* entropy feed distribution */
};
#ifdef _KERNEL
extern void get_random_bytes __P((void *, size_t));
extern u_int32_t arc4random __P((void));
+extern int arc4random_8 __P((void));
#endif /* _KERNEL */