Slight overhaul of arc4random() and friends.
One bug fixed: Use getmicrouptime() to trigger reseeds so that we cannot be tricked by a clock being stepped backwards. Express parameters in natural units and with natural names. Don't use struct timeval more than we need to. Various stylistic and readability polishing. Introduce arc4rand(void *ptr, u_int len, int reseed) function which returns a stream of pseudo-random bytes, observing the automatic reseed criteria as well as allowing forced reseeds. Rewrite arc4random() in terms of arc4rand(). Sponsored by: DARPA & NAI Labs.
This commit is contained in:
parent
a93cc5a1e7
commit
2c38619b52
@ -41,6 +41,8 @@
|
||||
.Fn srandom "u_long seed"
|
||||
.Ft u_long
|
||||
.Fn random "void"
|
||||
.Ft void
|
||||
.Fn arc4rand "void *ptr" "u_int length" "int reseed"
|
||||
.Ft u_int32_t
|
||||
.Fn arc4random "void"
|
||||
.Pp
|
||||
@ -68,12 +70,17 @@ function is entirely predictable, and is therefore not of use where
|
||||
knowledge of the sequence of numbers may be of benefit to an attacker.
|
||||
.Pp
|
||||
The
|
||||
.Fn arc4random
|
||||
.Fn arc4rand
|
||||
function will return very good quality random numbers, slightly better
|
||||
suited for security-related purposes.
|
||||
The random numbers from
|
||||
.Fn arc4random
|
||||
.Fn arc4rand
|
||||
are seeded from the entropy device if it is available.
|
||||
Automatic reseeds happen after a certain timeinterval and after a
|
||||
certain number of bytes have been delivered.
|
||||
A forced reseed can be forced by passing a non-zero value in the
|
||||
.Ar reseed
|
||||
argument.
|
||||
.Pp
|
||||
The
|
||||
.Fn read_random
|
||||
@ -90,16 +97,22 @@ is filled with no more than
|
||||
bytes. It is advised that
|
||||
.Fn read_random
|
||||
is not used; instead use
|
||||
.Fn arc4random .
|
||||
.Fn arc4rand
|
||||
.Pp
|
||||
All the bits generated by
|
||||
.Fn random ,
|
||||
.Fn arc4random
|
||||
.Fn arc4rand
|
||||
and
|
||||
.Fn read_random
|
||||
are usable. For example,
|
||||
.Sq Li random()&01
|
||||
will produce a random binary value.
|
||||
.Pp
|
||||
The
|
||||
.Fn arc4random
|
||||
is a convenience function which calls
|
||||
.Fn arc4rand
|
||||
to return a 32 bit pseudo-random integer.
|
||||
.Sh RETURN VALUES
|
||||
The
|
||||
.Fn random
|
||||
@ -114,10 +127,15 @@ The period of this random number generator is very large, approximately
|
||||
.if n 16*((2**31)\(mi1).
|
||||
.Pp
|
||||
The
|
||||
.Fn arc4rand
|
||||
function uses the RC4 algorithm to generate successive pseudo-random
|
||||
bytes.
|
||||
The
|
||||
.Fn arc4random
|
||||
function
|
||||
uses the RC4 algorithm to generate successive pseudo-random
|
||||
numbers in the range from 0 to
|
||||
uses
|
||||
.Fn arc4rand
|
||||
to generate pseudo-random numbers in the range from 0 to
|
||||
.if t 2\u\s732\s10\d\(mi1.
|
||||
.if n (2**32)\(mi1.
|
||||
.Pp
|
||||
|
@ -15,15 +15,15 @@
|
||||
#include <sys/libkern.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define ARC4_MAXRUNS 16384
|
||||
#define ARC4_RESEED_BYTES 65536
|
||||
#define ARC4_RESEED_SECONDS 300
|
||||
#define ARC4_KEYBYTES 32 /* 256 bit key */
|
||||
#define ARC4_KEYBYTES (256 / 8)
|
||||
|
||||
static u_int8_t arc4_i, arc4_j;
|
||||
static int arc4_initialized = 0;
|
||||
static int arc4_numruns = 0;
|
||||
static u_int8_t arc4_sbox[256];
|
||||
static struct timeval arc4_tv_nextreseed;
|
||||
static time_t arc4_t_reseed;
|
||||
|
||||
static u_int8_t arc4_randbyte(void);
|
||||
|
||||
@ -45,6 +45,7 @@ arc4_randomstir (void)
|
||||
{
|
||||
u_int8_t key[256];
|
||||
int r, n;
|
||||
struct timeval tv_now;
|
||||
|
||||
/*
|
||||
* XXX read_random() returns unsafe numbers if the entropy
|
||||
@ -52,21 +53,19 @@ arc4_randomstir (void)
|
||||
*/
|
||||
r = read_random(key, ARC4_KEYBYTES);
|
||||
/* If r == 0 || -1, just use what was on the stack. */
|
||||
if (r > 0)
|
||||
{
|
||||
if (r > 0) {
|
||||
for (n = r; n < sizeof(key); n++)
|
||||
key[n] = key[n % r];
|
||||
}
|
||||
|
||||
for (n = 0; n < 256; n++)
|
||||
{
|
||||
for (n = 0; n < 256; n++) {
|
||||
arc4_j = (arc4_j + arc4_sbox[n] + key[n]) % 256;
|
||||
arc4_swap(&arc4_sbox[n], &arc4_sbox[arc4_j]);
|
||||
}
|
||||
|
||||
/* Reset for next reseed cycle. */
|
||||
getmicrotime(&arc4_tv_nextreseed);
|
||||
arc4_tv_nextreseed.tv_sec += ARC4_RESEED_SECONDS;
|
||||
getmicrouptime(&tv_now);
|
||||
arc4_t_reseed = tv_now.tv_sec + ARC4_RESEED_SECONDS;
|
||||
arc4_numruns = 0;
|
||||
}
|
||||
|
||||
@ -111,27 +110,33 @@ arc4_randbyte(void)
|
||||
return arc4_sbox[arc4_t];
|
||||
}
|
||||
|
||||
u_int32_t
|
||||
arc4random(void)
|
||||
void
|
||||
arc4rand(void *ptr, u_int len, int reseed)
|
||||
{
|
||||
u_int32_t ret;
|
||||
struct timeval tv_now;
|
||||
u_char *p;
|
||||
struct timeval tv;
|
||||
|
||||
/* Initialize array if needed. */
|
||||
if (!arc4_initialized)
|
||||
arc4_init();
|
||||
|
||||
getmicrotime(&tv_now);
|
||||
if ((++arc4_numruns > ARC4_MAXRUNS) ||
|
||||
(tv_now.tv_sec > arc4_tv_nextreseed.tv_sec))
|
||||
{
|
||||
getmicrouptime(&tv);
|
||||
arc4_numruns += len;
|
||||
if (reseed ||
|
||||
(arc4_numruns > ARC4_RESEED_BYTES) ||
|
||||
(tv.tv_sec > arc4_t_reseed))
|
||||
arc4_randomstir();
|
||||
}
|
||||
|
||||
ret = arc4_randbyte();
|
||||
ret |= arc4_randbyte() << 8;
|
||||
ret |= arc4_randbyte() << 16;
|
||||
ret |= arc4_randbyte() << 24;
|
||||
p = ptr;
|
||||
while (len--)
|
||||
*p++ = arc4_randbyte();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
arc4random(void)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
arc4rand(&ret, sizeof ret, 0);
|
||||
return ret;
|
||||
}
|
||||
|
@ -64,7 +64,8 @@ static __inline u_long ulmax(u_long a, u_long b) { return (a > b ? a : b); }
|
||||
static __inline u_long ulmin(u_long a, u_long b) { return (a < b ? a : b); }
|
||||
|
||||
/* Prototypes for non-quad routines. */
|
||||
u_int32_t arc4random(void);
|
||||
uint32_t arc4random(void);
|
||||
void arc4rand(void *ptr, u_int len, int reseed);
|
||||
int bcmp(const void *, const void *, size_t);
|
||||
void *bsearch(const void *, const void *, size_t,
|
||||
size_t, int (*)(const void *, const void *));
|
||||
|
Loading…
Reference in New Issue
Block a user