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/crypt/arc4random.c | |
| 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 '')
| -rw-r--r-- | src/lib/libc/crypt/arc4random.c | 64 |
1 files changed, 63 insertions, 1 deletions
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> |
