summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorotto <>2008-03-16 19:47:43 +0000
committerotto <>2008-03-16 19:47:43 +0000
commite045e819cf6c3f1795515c3f3f6d661b69e1f66b (patch)
treef4249dd0935bf7960031a9fa944836948c49cad1
parenta8537602a33c58670952fc29ef3a95e13d478746 (diff)
downloadopenbsd-e045e819cf6c3f1795515c3f3f6d661b69e1f66b.tar.gz
openbsd-e045e819cf6c3f1795515c3f3f6d661b69e1f66b.tar.bz2
openbsd-e045e819cf6c3f1795515c3f3f6d661b69e1f66b.zip
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@
-rw-r--r--src/lib/libc/crypt/arc4random.323
-rw-r--r--src/lib/libc/crypt/arc4random.c64
2 files changed, 84 insertions, 3 deletions
diff --git a/src/lib/libc/crypt/arc4random.3 b/src/lib/libc/crypt/arc4random.3
index 31da5ec7ec..d32ea4a951 100644
--- a/src/lib/libc/crypt/arc4random.3
+++ b/src/lib/libc/crypt/arc4random.3
@@ -1,4 +1,4 @@
1.\" $OpenBSD: arc4random.3,v 1.22 2007/05/31 19:19:27 jmc Exp $ 1.\" $OpenBSD: arc4random.3,v 1.23 2008/03/16 19:47:43 otto Exp $
2.\" 2.\"
3.\" Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de> 3.\" Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
4.\" All rights reserved. 4.\" All rights reserved.
@@ -30,7 +30,7 @@
30.\" 30.\"
31.\" Manual page, using -mandoc macros 31.\" Manual page, using -mandoc macros
32.\" 32.\"
33.Dd $Mdocdate: May 31 2007 $ 33.Dd $Mdocdate: March 16 2008 $
34.Dt ARC4RANDOM 3 34.Dt ARC4RANDOM 3
35.Os 35.Os
36.Sh NAME 36.Sh NAME
@@ -43,6 +43,10 @@
43.Ft u_int32_t 43.Ft u_int32_t
44.Fn arc4random "void" 44.Fn arc4random "void"
45.Ft void 45.Ft void
46.Fn arc4random_buf "void *buf" "size_t nbytes"
47.Ft u_int32_t
48.Fn arc4random_uniform "u_int32_t upper_bound"
49.Ft void
46.Fn arc4random_stir "void" 50.Fn arc4random_stir "void"
47.Ft void 51.Ft void
48.Fn arc4random_addrandom "u_char *dat" "int datlen" 52.Fn arc4random_addrandom "u_char *dat" "int datlen"
@@ -73,6 +77,21 @@ versus the fast but poor quality interfaces described in
73and 77and
74.Xr drand48 3 . 78.Xr drand48 3 .
75.Pp 79.Pp
80.Fn arc4random_buf
81fills the region
82.Fa buf
83of length
84.Fa nbytes
85with ARC4-derived random data.
86.Pp
87.Fn arc4random_uniform
88will return a uniformly distributed random number less than
89.Fa upper_bound .
90.Fn arc4random_uniform
91is recommended over constructions like
92.Do Li arc4random() % upper_bound Dc
93as it avoids "modulo bias" when the upper bound is not a power of two.
94.Pp
76The 95The
77.Fn arc4random_stir 96.Fn arc4random_stir
78function reads data from 97function reads data from
diff --git a/src/lib/libc/crypt/arc4random.c b/src/lib/libc/crypt/arc4random.c
index 8604548f3f..bbe42bd204 100644
--- a/src/lib/libc/crypt/arc4random.c
+++ b/src/lib/libc/crypt/arc4random.c
@@ -1,7 +1,8 @@
1/* $OpenBSD: arc4random.c,v 1.17 2008/01/01 00:43:39 kurt Exp $ */ 1/* $OpenBSD: arc4random.c,v 1.18 2008/03/16 19:47:43 otto Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1996, David Mazieres <dm@uun.org> 4 * Copyright (c) 1996, David Mazieres <dm@uun.org>
5 * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
5 * 6 *
6 * Permission to use, copy, modify, and distribute this software for any 7 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above 8 * purpose with or without fee is hereby granted, provided that the above
@@ -34,6 +35,7 @@
34 */ 35 */
35 36
36#include <fcntl.h> 37#include <fcntl.h>
38#include <limits.h>
37#include <stdlib.h> 39#include <stdlib.h>
38#include <unistd.h> 40#include <unistd.h>
39#include <sys/types.h> 41#include <sys/types.h>
@@ -188,6 +190,66 @@ arc4random(void)
188 return val; 190 return val;
189} 191}
190 192
193void
194arc4random_buf(void *_buf, size_t n)
195{
196 u_char *buf = (u_char *)_buf;
197 _ARC4_LOCK();
198 if (!rs_initialized || arc4_stir_pid != getpid())
199 arc4_stir();
200 while (n--) {
201 if (--arc4_count <= 0)
202 arc4_stir();
203 buf[n] = arc4_getbyte();
204 }
205 _ARC4_UNLOCK();
206}
207
208/*
209 * Calculate a uniformly distributed random number less than upper_bound
210 * avoiding "modulo bias".
211 *
212 * Uniformity is achieved by generating new random numbers until the one
213 * returned is outside the range [0, 2**32 % upper_bound). This
214 * guarantees the selected random number will be inside
215 * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
216 * after reduction modulo upper_bound.
217 */
218u_int32_t
219arc4random_uniform(u_int32_t upper_bound)
220{
221 u_int32_t r, min;
222
223 if (upper_bound < 2)
224 return 0;
225
226#if (ULONG_MAX > 0xffffffffUL)
227 min = 0x100000000UL % upper_bound;
228#else
229 /* Calculate (2**32 % upper_bound) avoiding 64-bit math */
230 if (upper_bound > 0x80000000)
231 min = 1 + ~upper_bound; /* 2**32 - upper_bound */
232 else {
233 /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
234 min = ((0xffffffff - (upper_bound << 2)) + 1) % upper_bound;
235 }
236#endif
237
238 /*
239 * This could theoretically loop forever but each retry has
240 * p > 0.5 (worst case, usually far better) of selecting a
241 * number inside the range we need, so it should rarely need
242 * to re-roll.
243 */
244 for (;;) {
245 r = arc4random();
246 if (r >= min)
247 break;
248 }
249
250 return r % upper_bound;
251}
252
191#if 0 253#if 0
192/*-------- Test code for i386 --------*/ 254/*-------- Test code for i386 --------*/
193#include <stdio.h> 255#include <stdio.h>