Make arc4random far less greedy for entropy. Make arc4random actually
implement arc4 when used by threaded programs.
This commit is contained in:
parent
85a5a5ec09
commit
6e07f2d4dc
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: arc4random.c,v 1.10 2011/02/04 22:07:07 christos Exp $ */
|
||||
/* $NetBSD: arc4random.c,v 1.11 2012/02/27 04:25:12 tls Exp $ */
|
||||
/* $OpenBSD: arc4random.c,v 1.6 2001/06/05 05:05:38 pvalchev Exp $ */
|
||||
|
||||
/*
|
||||
@ -27,10 +27,11 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
__RCSID("$NetBSD: arc4random.c,v 1.10 2011/02/04 22:07:07 christos Exp $");
|
||||
__RCSID("$NetBSD: arc4random.c,v 1.11 2012/02/27 04:25:12 tls Exp $");
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include "namespace.h"
|
||||
#include "reentrant.h"
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
@ -44,13 +45,15 @@ __weak_alias(arc4random,_arc4random)
|
||||
#endif
|
||||
|
||||
struct arc4_stream {
|
||||
mutex_t mtx;
|
||||
uint8_t i;
|
||||
uint8_t j;
|
||||
uint8_t s[256];
|
||||
};
|
||||
|
||||
static int rs_initialized;
|
||||
static struct arc4_stream rs;
|
||||
/* XXX lint explodes with an internal error if only mtx is initialized! */
|
||||
static struct arc4_stream rs = { .i = 0, .mtx = MUTEX_INITIALIZER };
|
||||
|
||||
static inline void arc4_init(struct arc4_stream *);
|
||||
static inline void arc4_addrandom(struct arc4_stream *, u_char *, int);
|
||||
@ -89,40 +92,29 @@ arc4_addrandom(struct arc4_stream *as, u_char *dat, int datlen)
|
||||
static void
|
||||
arc4_stir(struct arc4_stream *as)
|
||||
{
|
||||
int fd;
|
||||
struct {
|
||||
struct timeval tv;
|
||||
u_int rnd[(128 - sizeof(struct timeval)) / sizeof(u_int)];
|
||||
} rdat;
|
||||
int rdat[128 / sizeof(int)];
|
||||
int n;
|
||||
int mib[2];
|
||||
unsigned int i;
|
||||
size_t len;
|
||||
|
||||
gettimeofday(&rdat.tv, NULL);
|
||||
fd = open("/dev/urandom", O_RDONLY);
|
||||
if (fd != -1) {
|
||||
read(fd, rdat.rnd, sizeof(rdat.rnd));
|
||||
close(fd);
|
||||
/*
|
||||
* This code once opened and read /dev/urandom on each
|
||||
* call. That causes repeated rekeying of the kernel stream
|
||||
* generator, which is very wasteful. Because of application
|
||||
* behavior, caching the fd doesn't really help. So we just
|
||||
* fill up the tank from sysctl, which is a tiny bit slower
|
||||
* for us but much friendlier to other entropy consumers.
|
||||
*/
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_URND;
|
||||
|
||||
for (i = 0; i < sizeof(rdat) / sizeof(int); i++) {
|
||||
len = sizeof(rdat[i]);
|
||||
if (sysctl(mib, 2, &rdat[i], &len, NULL, 0) == -1)
|
||||
abort();
|
||||
}
|
||||
#ifdef KERN_URND
|
||||
else {
|
||||
int mib[2];
|
||||
u_int i;
|
||||
size_t len;
|
||||
|
||||
/* Device could not be opened, we might be chrooted, take
|
||||
* randomness from sysctl. */
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_URND;
|
||||
|
||||
for (i = 0; i < sizeof(rdat.rnd) / sizeof(u_int); i++) {
|
||||
len = sizeof(u_int);
|
||||
if (sysctl(mib, 2, &rdat.rnd[i], &len, NULL, 0) == -1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* fd < 0 or failed sysctl ? Ah, what the heck. We'll just take
|
||||
* whatever was on the stack... */
|
||||
|
||||
arc4_addrandom(as, (void *) &rdat, sizeof(rdat));
|
||||
|
||||
@ -160,8 +152,8 @@ arc4_getword(struct arc4_stream *as)
|
||||
return val;
|
||||
}
|
||||
|
||||
void
|
||||
arc4random_stir(void)
|
||||
static inline void
|
||||
_arc4random_stir_unlocked(void)
|
||||
{
|
||||
if (!rs_initialized) {
|
||||
arc4_init(&rs);
|
||||
@ -171,23 +163,67 @@ arc4random_stir(void)
|
||||
}
|
||||
|
||||
void
|
||||
arc4random_addrandom(u_char *dat, int datlen)
|
||||
arc4random_stir(void)
|
||||
{
|
||||
#ifdef _REENTRANT
|
||||
if (__isthreaded) {
|
||||
mutex_lock(&rs.mtx);
|
||||
_arc4random_stir_unlocked();
|
||||
mutex_unlock(&rs.mtx);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
_arc4random_stir_unlocked();
|
||||
}
|
||||
|
||||
static inline void
|
||||
_arc4random_addrandom_unlocked(u_char *dat, int datlen)
|
||||
{
|
||||
if (!rs_initialized)
|
||||
arc4random_stir();
|
||||
arc4_stir(&rs);
|
||||
arc4_addrandom(&rs, dat, datlen);
|
||||
}
|
||||
|
||||
void
|
||||
arc4random_addrandom(u_char *dat, int datlen)
|
||||
{
|
||||
#ifdef _REENTRANT
|
||||
if (__isthreaded) {
|
||||
mutex_lock(&rs.mtx);
|
||||
_arc4random_addrandom_unlocked(dat, datlen);
|
||||
mutex_unlock(&rs.mtx);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
_arc4random_addrandom_unlocked(dat, datlen);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
_arc4random_unlocked(void)
|
||||
{
|
||||
if (!rs_initialized)
|
||||
arc4_stir(&rs);
|
||||
return arc4_getword(&rs);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
arc4random(void)
|
||||
{
|
||||
if (!rs_initialized)
|
||||
arc4random_stir();
|
||||
return arc4_getword(&rs);
|
||||
uint32_t v;
|
||||
#ifdef _REENTRANT
|
||||
if (__isthreaded) {
|
||||
mutex_lock(&rs.mtx);
|
||||
v = _arc4random_unlocked();
|
||||
mutex_unlock(&rs.mtx);
|
||||
return v;
|
||||
}
|
||||
#endif
|
||||
v = _arc4random_unlocked();
|
||||
return v;
|
||||
}
|
||||
|
||||
void
|
||||
arc4random_buf(void *buf, size_t len)
|
||||
static void
|
||||
_arc4random_buf_unlocked(void *buf, size_t len)
|
||||
{
|
||||
uint8_t *bp = buf;
|
||||
uint8_t *ep = bp + len;
|
||||
@ -200,6 +236,20 @@ arc4random_buf(void *buf, size_t len)
|
||||
*bp++ = arc4_getbyte(&rs);
|
||||
}
|
||||
|
||||
void
|
||||
arc4random_buf(void *buf, size_t len)
|
||||
{
|
||||
#ifdef _REENTRANT
|
||||
if (__isthreaded) {
|
||||
mutex_lock(&rs.mtx);
|
||||
_arc4random_buf_unlocked(buf, len);
|
||||
mutex_unlock(&rs.mtx);
|
||||
return;
|
||||
} else
|
||||
#endif
|
||||
_arc4random_buf_unlocked(buf, len);
|
||||
}
|
||||
|
||||
/*-
|
||||
* Written by Damien Miller.
|
||||
* With simplifications by Jinmei Tatuya.
|
||||
@ -216,8 +266,8 @@ arc4random_buf(void *buf, size_t len)
|
||||
* [2^32 % upper_bound, 2^32[ which maps back to
|
||||
* [0, upper_bound[ after reduction modulo upper_bound.
|
||||
*/
|
||||
uint32_t
|
||||
arc4random_uniform(uint32_t upper_bound)
|
||||
static uint32_t
|
||||
_arc4random_uniform_unlocked(uint32_t upper_bound)
|
||||
{
|
||||
uint32_t r, min;
|
||||
|
||||
@ -243,7 +293,7 @@ arc4random_uniform(uint32_t upper_bound)
|
||||
* to re-roll (at all).
|
||||
*/
|
||||
if (!rs_initialized)
|
||||
arc4random_stir();
|
||||
arc4_stir(&rs);
|
||||
if (arc4_getbyte(&rs) & 1)
|
||||
(void)arc4_getbyte(&rs);
|
||||
do
|
||||
@ -253,24 +303,18 @@ arc4random_uniform(uint32_t upper_bound)
|
||||
return r % upper_bound;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/*-------- Test code for i386 --------*/
|
||||
#include <stdio.h>
|
||||
#include <machine/pctr.h>
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
uint32_t
|
||||
arc4random_uniform(uint32_t upper_bound)
|
||||
{
|
||||
const int iter = 1000000;
|
||||
int i;
|
||||
pctrval v;
|
||||
|
||||
v = rdtsc();
|
||||
for (i = 0; i < iter; i++)
|
||||
arc4random();
|
||||
v = rdtsc() - v;
|
||||
v /= iter;
|
||||
|
||||
printf("%qd cycles\n", v);
|
||||
}
|
||||
uint32_t v;
|
||||
#ifdef _REENTRANT
|
||||
if (__isthreaded) {
|
||||
mutex_lock(&rs.mtx);
|
||||
v = _arc4random_uniform_unlocked(upper_bound);
|
||||
mutex_unlock(&rs.mtx);
|
||||
return v;
|
||||
}
|
||||
#endif
|
||||
v = _arc4random_uniform_unlocked(upper_bound);
|
||||
return v;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user