diff options
author | otto <> | 2008-03-16 19:47:43 +0000 |
---|---|---|
committer | otto <> | 2008-03-16 19:47:43 +0000 |
commit | e045e819cf6c3f1795515c3f3f6d661b69e1f66b (patch) | |
tree | f4249dd0935bf7960031a9fa944836948c49cad1 | |
parent | a8537602a33c58670952fc29ef3a95e13d478746 (diff) | |
download | openbsd-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.3 | 23 | ||||
-rw-r--r-- | src/lib/libc/crypt/arc4random.c | 64 |
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 | |||
73 | and | 77 | and |
74 | .Xr drand48 3 . | 78 | .Xr drand48 3 . |
75 | .Pp | 79 | .Pp |
80 | .Fn arc4random_buf | ||
81 | fills the region | ||
82 | .Fa buf | ||
83 | of length | ||
84 | .Fa nbytes | ||
85 | with ARC4-derived random data. | ||
86 | .Pp | ||
87 | .Fn arc4random_uniform | ||
88 | will return a uniformly distributed random number less than | ||
89 | .Fa upper_bound . | ||
90 | .Fn arc4random_uniform | ||
91 | is recommended over constructions like | ||
92 | .Do Li arc4random() % upper_bound Dc | ||
93 | as it avoids "modulo bias" when the upper bound is not a power of two. | ||
94 | .Pp | ||
76 | The | 95 | The |
77 | .Fn arc4random_stir | 96 | .Fn arc4random_stir |
78 | function reads data from | 97 | function 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 | ||
193 | void | ||
194 | arc4random_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 | */ | ||
218 | u_int32_t | ||
219 | arc4random_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> |