summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/rnd.c180
1 files changed, 89 insertions, 91 deletions
diff --git a/sys/dev/rnd.c b/sys/dev/rnd.c
index 77a4c54e419..1f49bb0af19 100644
--- a/sys/dev/rnd.c
+++ b/sys/dev/rnd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rnd.c,v 1.39 2000/06/08 02:39:08 mickey Exp $ */
+/* $OpenBSD: rnd.c,v 1.40 2000/06/16 19:18:51 deraadt Exp $ */
/*
* random.c -- A strong random number generator
@@ -229,6 +229,13 @@
* 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 SHA transform was taken from Peter Gutmann's
+ * implementation, which has been placed in the public domain.
+ * 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.
@@ -354,8 +361,8 @@ int rnd_debug = 0x0000;
*/
/* pIII/333 reported to have some drops w/ these numbers */
-#define QEVLEN (1024 / sizeof(struct rand_event))
-#define QEVSLOW (QEVLEN * 3 / 4) /* yet another 0.75 for 60-minutes hour /-; */
+#define QEVLEN 96
+#define QEVSLOW 64 /* yet another 0.75 for 60-minutes hour /-; */
#define QEVSBITS 12
/* There is actually only one of these, globally. */
@@ -365,6 +372,7 @@ struct random_bucket {
u_char input_rotate;
u_int32_t pool[POOLWORDS];
u_int asleep;
+ u_int queued;
u_int tmo;
};
@@ -385,8 +393,9 @@ struct arc4_stream {
};
struct rand_event {
+ struct rand_event *re_next;
struct timer_rand_state *re_state;
- u_int re_nbits;
+ u_char re_nbits;
u_int re_time;
u_int re_val;
};
@@ -396,7 +405,8 @@ struct random_bucket random_state;
struct arc4_stream arc4random_state;
struct timer_rand_state rnd_states[RND_SRC_NUM];
struct rand_event rnd_event_space[QEVLEN];
-struct rand_event *rnd_event_head, *rnd_event_tail;
+struct rand_event *rnd_event_q;
+struct rand_event *rnd_event_free;
int rnd_attached;
int arc4random_initialized;
@@ -412,46 +422,6 @@ static __inline u_int32_t roll(u_int32_t w, int i)
return w;
}
-/* must be called at a proper spl, returns ptr to the next event */
-static __inline struct rand_event *
-rnd_get(void)
-{
- struct rand_event *p = rnd_event_tail;
-
- if (p == rnd_event_head)
- return NULL;
-
- if (p + 1 == &rnd_event_space[QEVLEN])
- rnd_event_tail = rnd_event_space;
- else
- rnd_event_tail++;
-
- return p;
-}
-
-/* must be called at a proper spl, returns next available item */
-static __inline struct rand_event *
-rnd_put(void)
-{
- struct rand_event *p = rnd_event_head + 1;
-
- if (p == &rnd_event_space[QEVLEN])
- p = rnd_event_space;
-
- if (p == rnd_event_tail)
- return NULL;
-
- return rnd_event_head = p;
-}
-
-/* must be called at a proper spl, returns number of items in the queue */
-static __inline int
-rnd_qlen(void)
-{
- int len = rnd_event_head - rnd_event_tail;
- return (len < 0)? -len : len;
-}
-
void dequeue_randomness __P((void *));
static __inline void add_entropy_words __P((const u_int32_t *, u_int n));
@@ -565,6 +535,8 @@ void
randomattach(void)
{
int i;
+ struct timeval tv;
+ struct rand_event *rep;
if (rnd_attached) {
#ifdef RNDEBUG
@@ -580,17 +552,16 @@ randomattach(void)
rnd_states[RND_SRC_TRUE].max_entropy = 1;
bzero(&rndstats, sizeof(rndstats));
-
bzero(&rnd_event_space, sizeof(rnd_event_space));
- rnd_event_head = rnd_event_tail = rnd_event_space;
-
+ rnd_event_free = rnd_event_space;
+ for (rep = rnd_event_space; rep < &rnd_event_space[QEVLEN-1]; rep++)
+ rep->re_next = rep + 1;
for (i = 0; i < 256; i++)
arc4random_state.s[i] = i;
- arc4_reinit(NULL);
-
- timeout_set(&rnd_timeout, dequeue_randomness, &random_state);
+ microtime(&tv);
+ timeout_set(&rnd_timeout, dequeue_randomness, NULL);
timeout_set(&arc4_timeout, arc4_reinit, NULL);
-
+ arc4_reinit(NULL);
rnd_attached = 1;
}
@@ -637,10 +608,13 @@ add_entropy_words(buf, n)
0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278
};
+ u_int i;
+ int new_rotate;
+ u_int32_t w;
while (n--) {
- register u_int32_t w = roll(*buf, random_state.input_rotate);
- register u_int i = random_state.add_ptr =
+ w = roll(*buf, random_state.input_rotate);
+ i = random_state.add_ptr =
(random_state.add_ptr - 1) & (POOLWORDS - 1);
/*
* Normally, we add 7 bits of rotation to the pool.
@@ -648,16 +622,18 @@ add_entropy_words(buf, n)
* rotation, so that successive passes spread the
* input bits across the pool evenly.
*/
- random_state.input_rotate =
- (random_state.input_rotate + (i? 7 : 14)) & 31;
+ new_rotate = random_state.input_rotate + 14;
+ if (i)
+ new_rotate = random_state.input_rotate + 7;
+ random_state.input_rotate = new_rotate & 31;
/* XOR in the various taps */
- w ^= random_state.pool[(i+TAP1) & (POOLWORDS-1)] ^
- random_state.pool[(i+TAP2) & (POOLWORDS-1)] ^
- random_state.pool[(i+TAP3) & (POOLWORDS-1)] ^
- random_state.pool[(i+TAP4) & (POOLWORDS-1)] ^
- random_state.pool[(i+TAP5) & (POOLWORDS-1)] ^
- random_state.pool[i];
+ w ^= random_state.pool[(i+TAP1)&(POOLWORDS-1)];
+ w ^= random_state.pool[(i+TAP2)&(POOLWORDS-1)];
+ w ^= random_state.pool[(i+TAP3)&(POOLWORDS-1)];
+ w ^= random_state.pool[(i+TAP4)&(POOLWORDS-1)];
+ w ^= random_state.pool[(i+TAP5)&(POOLWORDS-1)];
+ w ^= random_state.pool[i];
random_state.pool[i] = (w >> 3) ^ twist_table[w & 7];
}
}
@@ -678,7 +654,6 @@ void
enqueue_randomness(state, val)
int state, val;
{
- struct random_bucket *rs = &random_state;
struct timer_rand_state *p;
struct timeval tv;
register struct rand_event *rep;
@@ -746,7 +721,7 @@ enqueue_randomness(state, val)
* the logic is to drop low-entropy entries,
* in hope for dequeuing to be more sourcefull
*/
- if (rnd_qlen() > QEVSLOW && nbits < QEVSBITS) {
+ if (random_state.queued > QEVSLOW && nbits < QEVSBITS) {
rndstats.rnd_drople++;
return;
}
@@ -757,23 +732,29 @@ enqueue_randomness(state, val)
nbits = 8 * sizeof(val) - 1;
s = splhigh();
- if ((rep = rnd_put()) == NULL) {
+ if ((rep = rnd_event_free) == NULL) {
rndstats.rnd_drops++;
splx(s);
return;
}
+ rnd_event_free = rep->re_next;
rep->re_state = p;
rep->re_nbits = nbits;
rep->re_time = time;
rep->re_val = val;
+ rep->re_next = rnd_event_q;
+ rnd_event_q = rep;
+ rep = rep->re_next;
+ random_state.queued++;
+
rndstats.rnd_enqs++;
rndstats.rnd_ed[nbits]++;
rndstats.rnd_sc[state]++;
rndstats.rnd_sb[state] += nbits;
- if (rnd_qlen() > QEVSLOW/2 && !rs->tmo) {
+ if (++random_state.queued > QEVSLOW/2 && !random_state.tmo) {
random_state.tmo++;
timeout_add(&rnd_timeout, 1);
}
@@ -784,46 +765,59 @@ void
dequeue_randomness(v)
void *v;
{
- struct random_bucket *rs = v;
register struct rand_event *rep;
- u_int32_t buf[2];
+ u_int32_t val, time;
u_int nbits;
int s;
timeout_del(&rnd_timeout);
rndstats.rnd_deqs++;
- s = splhigh();
- while ((rep = rnd_get())) {
+ do {
+ s = splhigh();
+ if (rnd_event_q == NULL) {
+ splx(s);
+ break;
+ }
+ rep = rnd_event_q;
+ rnd_event_q = rep->re_next;
+ random_state.queued--;
- buf[0] = rep->re_time;
- buf[1] = rep->re_val;
+ val = rep->re_val;
+ time = rep->re_time;
nbits = rep->re_nbits;
+
+ rep->re_next = rnd_event_free;
+ rnd_event_free = rep;
splx(s);
- add_entropy_words(buf, 2);
+ /* Prevent overflow */
+ if ((random_state.entropy_count + nbits) > POOLBITS &&
+ arc4random_state.cnt > 253)
+ arc4_stir();
+ add_entropy_words(&val, 1);
+ add_entropy_words(&time, 1);
+
+ random_state.entropy_count += nbits;
rndstats.rnd_total += nbits;
- rs->entropy_count += nbits;
- if (rs->entropy_count > POOLBITS)
- rs->entropy_count = POOLBITS;
+ if (random_state.entropy_count > POOLBITS)
+ random_state.entropy_count = POOLBITS;
- if (rs->asleep && rs->entropy_count > 8) {
+ if (random_state.entropy_count > 8 &&
+ random_state.asleep != 0) {
#ifdef RNDEBUG
if (rnd_debug & RD_WAIT)
printf("rnd: wakeup[%u]{%u}\n",
- rs->asleep,
- rs->entropy_count);
+ random_state.asleep,
+ random_state.entropy_count);
#endif
- rs->asleep--;
- wakeup((void *)&rs->asleep);
+ random_state.asleep--;
+ wakeup(&random_state.asleep);
}
+ } while(1);
- s = splhigh();
- }
-
- rs->tmo = 0;
- splx(s);
+ random_state.tmo = 0;
}
#if POOLWORDS % 16
@@ -841,16 +835,19 @@ extract_entropy(buf, nbytes)
register u_int8_t *buf;
int nbytes;
{
- struct random_bucket *rs = &random_state;
MD5_CTX tmp;
u_char buffer[16];
add_timer_randomness(nbytes);
- if (rs->entropy_count / 8 > nbytes)
- rs->entropy_count -= nbytes*8;
+ /* Redundant, but just in case... */
+ if (random_state.entropy_count > POOLBITS)
+ random_state.entropy_count = POOLBITS;
+
+ if (random_state.entropy_count / 8 > nbytes)
+ random_state.entropy_count -= nbytes*8;
else
- rs->entropy_count = 0;
+ random_state.entropy_count = 0;
while (nbytes) {
register u_char *p = buf;
@@ -863,7 +860,8 @@ extract_entropy(buf, nbytes)
/* Hash the pool to get the output */
MD5Init(&tmp);
- MD5Update(&tmp, (u_int8_t*)rs->pool, sizeof(rs->pool));
+ MD5Update(&tmp, (u_int8_t*)random_state.pool,
+ sizeof(random_state.pool));
MD5Final(p, &tmp);
/*