Browse Source

diff from djm@ committed at his request:

introduce two new APIs for requesting strong random numbers:
arc4random_buf() - fill an arbitrary memory range with random numbers
arc4random_uniform() - return a uniformly distributed random number
below
a specified upper bound, avoiding the bias that comes from a naive
"arc4random() % upper_bound" construction.
these mirror similarly-named functions in the kernel;
lots of discussion deraadt@ mcbride@
OPENBSD_4_4
otto 16 years ago
parent
commit
ffe451fa53
3 changed files with 89 additions and 4 deletions
  1. +5
    -1
      src/include/stdlib.h
  2. +21
    -2
      src/lib/libc/crypt/arc4random.3
  3. +63
    -1
      src/lib/libc/crypt/arc4random.c

+ 5
- 1
src/include/stdlib.h View File

@ -1,4 +1,4 @@
/* $OpenBSD: stdlib.h,v 1.40 2007/09/03 14:37:02 millert Exp $ */
/* $OpenBSD: stdlib.h,v 1.41 2008/03/16 19:47:43 otto Exp $ */
/* $NetBSD: stdlib.h,v 1.25 1995/12/27 21:19:08 jtc Exp $ */
/*-
@ -272,6 +272,10 @@ u_int32_t arc4random(void);
void arc4random_stir(void);
void arc4random_addrandom(unsigned char *, int)
__attribute__((__bounded__ (__string__,1,2)));
u_int32_t arc4random_uniform(u_int32_t);
void arc4random_buf(void *, size_t)
__attribute__((__bounded__ (__string__,1,2)));
#endif /* __BSD_VISIBLE */
__END_DECLS


+ 21
- 2
src/lib/libc/crypt/arc4random.3 View File

@ -1,4 +1,4 @@
.\" $OpenBSD: arc4random.3,v 1.22 2007/05/31 19:19:27 jmc Exp $
.\" $OpenBSD: arc4random.3,v 1.23 2008/03/16 19:47:43 otto Exp $
.\"
.\" Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
.\" All rights reserved.
@ -30,7 +30,7 @@
.\"
.\" Manual page, using -mandoc macros
.\"
.Dd $Mdocdate: May 31 2007 $
.Dd $Mdocdate: March 16 2008 $
.Dt ARC4RANDOM 3
.Os
.Sh NAME
@ -43,6 +43,10 @@
.Ft u_int32_t
.Fn arc4random "void"
.Ft void
.Fn arc4random_buf "void *buf" "size_t nbytes"
.Ft u_int32_t
.Fn arc4random_uniform "u_int32_t upper_bound"
.Ft void
.Fn arc4random_stir "void"
.Ft void
.Fn arc4random_addrandom "u_char *dat" "int datlen"
@ -73,6 +77,21 @@ versus the fast but poor quality interfaces described in
and
.Xr drand48 3 .
.Pp
.Fn arc4random_buf
fills the region
.Fa buf
of length
.Fa nbytes
with ARC4-derived random data.
.Pp
.Fn arc4random_uniform
will return a uniformly distributed random number less than
.Fa upper_bound .
.Fn arc4random_uniform
is recommended over constructions like
.Do Li arc4random() % upper_bound Dc
as it avoids "modulo bias" when the upper bound is not a power of two.
.Pp
The
.Fn arc4random_stir
function reads data from


+ 63
- 1
src/lib/libc/crypt/arc4random.c View File

@ -1,7 +1,8 @@
/* $OpenBSD: arc4random.c,v 1.17 2008/01/01 00:43:39 kurt Exp $ */
/* $OpenBSD: arc4random.c,v 1.18 2008/03/16 19:47:43 otto Exp $ */
/*
* Copyright (c) 1996, David Mazieres <dm@uun.org>
* Copyright (c) 2008, Damien Miller <djm@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -34,6 +35,7 @@
*/
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
@ -188,6 +190,66 @@ arc4random(void)
return val;
}
void
arc4random_buf(void *_buf, size_t n)
{
u_char *buf = (u_char *)_buf;
_ARC4_LOCK();
if (!rs_initialized || arc4_stir_pid != getpid())
arc4_stir();
while (n--) {
if (--arc4_count <= 0)
arc4_stir();
buf[n] = arc4_getbyte();
}
_ARC4_UNLOCK();
}
/*
* Calculate a uniformly distributed random number less than upper_bound
* avoiding "modulo bias".
*
* Uniformity is achieved by generating new random numbers until the one
* returned is outside the range [0, 2**32 % upper_bound). This
* guarantees the selected random number will be inside
* [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
* after reduction modulo upper_bound.
*/
u_int32_t
arc4random_uniform(u_int32_t upper_bound)
{
u_int32_t r, min;
if (upper_bound < 2)
return 0;
#if (ULONG_MAX > 0xffffffffUL)
min = 0x100000000UL % upper_bound;
#else
/* Calculate (2**32 % upper_bound) avoiding 64-bit math */
if (upper_bound > 0x80000000)
min = 1 + ~upper_bound; /* 2**32 - upper_bound */
else {
/* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
min = ((0xffffffff - (upper_bound << 2)) + 1) % upper_bound;
}
#endif
/*
* This could theoretically loop forever but each retry has
* p > 0.5 (worst case, usually far better) of selecting a
* number inside the range we need, so it should rarely need
* to re-roll.
*/
for (;;) {
r = arc4random();
if (r >= min)
break;
}
return r % upper_bound;
}
#if 0
/*-------- Test code for i386 --------*/
#include <stdio.h>


Loading…
Cancel
Save