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 /src/lib/libc | |
| 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@
Diffstat (limited to 'src/lib/libc')
| -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> |
