ipc/chromium/src/third_party/libevent/arc4random.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* Portable arc4random.c based on arc4random.c from OpenBSD.
michael@0 2 * Portable version by Chris Davis, adapted for Libevent by Nick Mathewson
michael@0 3 * Copyright (c) 2010 Chris Davis, Niels Provos, and Nick Mathewson
michael@0 4 * Copyright (c) 2010-2012 Niels Provos and Nick Mathewson
michael@0 5 *
michael@0 6 * Note that in Libevent, this file isn't compiled directly. Instead,
michael@0 7 * it's included from evutil_rand.c
michael@0 8 */
michael@0 9
michael@0 10 /*
michael@0 11 * Copyright (c) 1996, David Mazieres <dm@uun.org>
michael@0 12 * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
michael@0 13 *
michael@0 14 * Permission to use, copy, modify, and distribute this software for any
michael@0 15 * purpose with or without fee is hereby granted, provided that the above
michael@0 16 * copyright notice and this permission notice appear in all copies.
michael@0 17 *
michael@0 18 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
michael@0 19 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
michael@0 20 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
michael@0 21 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
michael@0 22 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
michael@0 23 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
michael@0 24 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
michael@0 25 */
michael@0 26
michael@0 27 /*
michael@0 28 * Arc4 random number generator for OpenBSD.
michael@0 29 *
michael@0 30 * This code is derived from section 17.1 of Applied Cryptography,
michael@0 31 * second edition, which describes a stream cipher allegedly
michael@0 32 * compatible with RSA Labs "RC4" cipher (the actual description of
michael@0 33 * which is a trade secret). The same algorithm is used as a stream
michael@0 34 * cipher called "arcfour" in Tatu Ylonen's ssh package.
michael@0 35 *
michael@0 36 * Here the stream cipher has been modified always to include the time
michael@0 37 * when initializing the state. That makes it impossible to
michael@0 38 * regenerate the same random sequence twice, so this can't be used
michael@0 39 * for encryption, but will generate good random numbers.
michael@0 40 *
michael@0 41 * RC4 is a registered trademark of RSA Laboratories.
michael@0 42 */
michael@0 43
michael@0 44 #ifndef ARC4RANDOM_EXPORT
michael@0 45 #define ARC4RANDOM_EXPORT
michael@0 46 #endif
michael@0 47
michael@0 48 #ifndef ARC4RANDOM_UINT32
michael@0 49 #define ARC4RANDOM_UINT32 uint32_t
michael@0 50 #endif
michael@0 51
michael@0 52 #ifndef ARC4RANDOM_NO_INCLUDES
michael@0 53 #ifdef WIN32
michael@0 54 #include <wincrypt.h>
michael@0 55 #include <process.h>
michael@0 56 #else
michael@0 57 #include <fcntl.h>
michael@0 58 #include <unistd.h>
michael@0 59 #include <sys/param.h>
michael@0 60 #include <sys/time.h>
michael@0 61 #ifdef _EVENT_HAVE_SYS_SYSCTL_H
michael@0 62 #include <sys/sysctl.h>
michael@0 63 #endif
michael@0 64 #endif
michael@0 65 #include <limits.h>
michael@0 66 #include <stdlib.h>
michael@0 67 #include <string.h>
michael@0 68 #endif
michael@0 69
michael@0 70 /* Add platform entropy 32 bytes (256 bits) at a time. */
michael@0 71 #define ADD_ENTROPY 32
michael@0 72
michael@0 73 /* Re-seed from the platform RNG after generating this many bytes. */
michael@0 74 #define BYTES_BEFORE_RESEED 1600000
michael@0 75
michael@0 76 struct arc4_stream {
michael@0 77 unsigned char i;
michael@0 78 unsigned char j;
michael@0 79 unsigned char s[256];
michael@0 80 };
michael@0 81
michael@0 82 #ifdef WIN32
michael@0 83 #define getpid _getpid
michael@0 84 #define pid_t int
michael@0 85 #endif
michael@0 86
michael@0 87 static int rs_initialized;
michael@0 88 static struct arc4_stream rs;
michael@0 89 static pid_t arc4_stir_pid;
michael@0 90 static int arc4_count;
michael@0 91 static int arc4_seeded_ok;
michael@0 92
michael@0 93 static inline unsigned char arc4_getbyte(void);
michael@0 94
michael@0 95 static inline void
michael@0 96 arc4_init(void)
michael@0 97 {
michael@0 98 int n;
michael@0 99
michael@0 100 for (n = 0; n < 256; n++)
michael@0 101 rs.s[n] = n;
michael@0 102 rs.i = 0;
michael@0 103 rs.j = 0;
michael@0 104 }
michael@0 105
michael@0 106 static inline void
michael@0 107 arc4_addrandom(const unsigned char *dat, int datlen)
michael@0 108 {
michael@0 109 int n;
michael@0 110 unsigned char si;
michael@0 111
michael@0 112 rs.i--;
michael@0 113 for (n = 0; n < 256; n++) {
michael@0 114 rs.i = (rs.i + 1);
michael@0 115 si = rs.s[rs.i];
michael@0 116 rs.j = (rs.j + si + dat[n % datlen]);
michael@0 117 rs.s[rs.i] = rs.s[rs.j];
michael@0 118 rs.s[rs.j] = si;
michael@0 119 }
michael@0 120 rs.j = rs.i;
michael@0 121 }
michael@0 122
michael@0 123 #ifndef WIN32
michael@0 124 static ssize_t
michael@0 125 read_all(int fd, unsigned char *buf, size_t count)
michael@0 126 {
michael@0 127 size_t numread = 0;
michael@0 128 ssize_t result;
michael@0 129
michael@0 130 while (numread < count) {
michael@0 131 result = read(fd, buf+numread, count-numread);
michael@0 132 if (result<0)
michael@0 133 return -1;
michael@0 134 else if (result == 0)
michael@0 135 break;
michael@0 136 numread += result;
michael@0 137 }
michael@0 138
michael@0 139 return (ssize_t)numread;
michael@0 140 }
michael@0 141 #endif
michael@0 142
michael@0 143 #ifdef WIN32
michael@0 144 #define TRY_SEED_WIN32
michael@0 145 static int
michael@0 146 arc4_seed_win32(void)
michael@0 147 {
michael@0 148 /* This is adapted from Tor's crypto_seed_rng() */
michael@0 149 static int provider_set = 0;
michael@0 150 static HCRYPTPROV provider;
michael@0 151 unsigned char buf[ADD_ENTROPY];
michael@0 152
michael@0 153 if (!provider_set) {
michael@0 154 if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
michael@0 155 CRYPT_VERIFYCONTEXT)) {
michael@0 156 if (GetLastError() != (DWORD)NTE_BAD_KEYSET)
michael@0 157 return -1;
michael@0 158 }
michael@0 159 provider_set = 1;
michael@0 160 }
michael@0 161 if (!CryptGenRandom(provider, sizeof(buf), buf))
michael@0 162 return -1;
michael@0 163 arc4_addrandom(buf, sizeof(buf));
michael@0 164 memset(buf, 0, sizeof(buf));
michael@0 165 arc4_seeded_ok = 1;
michael@0 166 return 0;
michael@0 167 }
michael@0 168 #endif
michael@0 169
michael@0 170 #if defined(_EVENT_HAVE_SYS_SYSCTL_H) && defined(_EVENT_HAVE_SYSCTL)
michael@0 171 #if _EVENT_HAVE_DECL_CTL_KERN && _EVENT_HAVE_DECL_KERN_RANDOM && _EVENT_HAVE_DECL_RANDOM_UUID
michael@0 172 #define TRY_SEED_SYSCTL_LINUX
michael@0 173 static int
michael@0 174 arc4_seed_sysctl_linux(void)
michael@0 175 {
michael@0 176 /* Based on code by William Ahern, this function tries to use the
michael@0 177 * RANDOM_UUID sysctl to get entropy from the kernel. This can work
michael@0 178 * even if /dev/urandom is inaccessible for some reason (e.g., we're
michael@0 179 * running in a chroot). */
michael@0 180 int mib[] = { CTL_KERN, KERN_RANDOM, RANDOM_UUID };
michael@0 181 unsigned char buf[ADD_ENTROPY];
michael@0 182 size_t len, n;
michael@0 183 unsigned i;
michael@0 184 int any_set;
michael@0 185
michael@0 186 memset(buf, 0, sizeof(buf));
michael@0 187
michael@0 188 for (len = 0; len < sizeof(buf); len += n) {
michael@0 189 n = sizeof(buf) - len;
michael@0 190
michael@0 191 if (0 != sysctl(mib, 3, &buf[len], &n, NULL, 0))
michael@0 192 return -1;
michael@0 193 }
michael@0 194 /* make sure that the buffer actually got set. */
michael@0 195 for (i=0,any_set=0; i<sizeof(buf); ++i) {
michael@0 196 any_set |= buf[i];
michael@0 197 }
michael@0 198 if (!any_set)
michael@0 199 return -1;
michael@0 200
michael@0 201 arc4_addrandom(buf, sizeof(buf));
michael@0 202 memset(buf, 0, sizeof(buf));
michael@0 203 arc4_seeded_ok = 1;
michael@0 204 return 0;
michael@0 205 }
michael@0 206 #endif
michael@0 207
michael@0 208 #if _EVENT_HAVE_DECL_CTL_KERN && _EVENT_HAVE_DECL_KERN_ARND
michael@0 209 #define TRY_SEED_SYSCTL_BSD
michael@0 210 static int
michael@0 211 arc4_seed_sysctl_bsd(void)
michael@0 212 {
michael@0 213 /* Based on code from William Ahern and from OpenBSD, this function
michael@0 214 * tries to use the KERN_ARND syscall to get entropy from the kernel.
michael@0 215 * This can work even if /dev/urandom is inaccessible for some reason
michael@0 216 * (e.g., we're running in a chroot). */
michael@0 217 int mib[] = { CTL_KERN, KERN_ARND };
michael@0 218 unsigned char buf[ADD_ENTROPY];
michael@0 219 size_t len, n;
michael@0 220 int i, any_set;
michael@0 221
michael@0 222 memset(buf, 0, sizeof(buf));
michael@0 223
michael@0 224 len = sizeof(buf);
michael@0 225 if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) {
michael@0 226 for (len = 0; len < sizeof(buf); len += sizeof(unsigned)) {
michael@0 227 n = sizeof(unsigned);
michael@0 228 if (n + len > sizeof(buf))
michael@0 229 n = len - sizeof(buf);
michael@0 230 if (sysctl(mib, 2, &buf[len], &n, NULL, 0) == -1)
michael@0 231 return -1;
michael@0 232 }
michael@0 233 }
michael@0 234 /* make sure that the buffer actually got set. */
michael@0 235 for (i=any_set=0; i<sizeof(buf); ++i) {
michael@0 236 any_set |= buf[i];
michael@0 237 }
michael@0 238 if (!any_set)
michael@0 239 return -1;
michael@0 240
michael@0 241 arc4_addrandom(buf, sizeof(buf));
michael@0 242 memset(buf, 0, sizeof(buf));
michael@0 243 arc4_seeded_ok = 1;
michael@0 244 return 0;
michael@0 245 }
michael@0 246 #endif
michael@0 247 #endif /* defined(_EVENT_HAVE_SYS_SYSCTL_H) */
michael@0 248
michael@0 249 #ifdef __linux__
michael@0 250 #define TRY_SEED_PROC_SYS_KERNEL_RANDOM_UUID
michael@0 251 static int
michael@0 252 arc4_seed_proc_sys_kernel_random_uuid(void)
michael@0 253 {
michael@0 254 /* Occasionally, somebody will make /proc/sys accessible in a chroot,
michael@0 255 * but not /dev/urandom. Let's try /proc/sys/kernel/random/uuid.
michael@0 256 * Its format is stupid, so we need to decode it from hex.
michael@0 257 */
michael@0 258 int fd;
michael@0 259 char buf[128];
michael@0 260 unsigned char entropy[64];
michael@0 261 int bytes, n, i, nybbles;
michael@0 262 for (bytes = 0; bytes<ADD_ENTROPY; ) {
michael@0 263 fd = evutil_open_closeonexec("/proc/sys/kernel/random/uuid", O_RDONLY, 0);
michael@0 264 if (fd < 0)
michael@0 265 return -1;
michael@0 266 n = read(fd, buf, sizeof(buf));
michael@0 267 close(fd);
michael@0 268 if (n<=0)
michael@0 269 return -1;
michael@0 270 memset(entropy, 0, sizeof(entropy));
michael@0 271 for (i=nybbles=0; i<n; ++i) {
michael@0 272 if (EVUTIL_ISXDIGIT(buf[i])) {
michael@0 273 int nyb = evutil_hex_char_to_int(buf[i]);
michael@0 274 if (nybbles & 1) {
michael@0 275 entropy[nybbles/2] |= nyb;
michael@0 276 } else {
michael@0 277 entropy[nybbles/2] |= nyb<<4;
michael@0 278 }
michael@0 279 ++nybbles;
michael@0 280 }
michael@0 281 }
michael@0 282 if (nybbles < 2)
michael@0 283 return -1;
michael@0 284 arc4_addrandom(entropy, nybbles/2);
michael@0 285 bytes += nybbles/2;
michael@0 286 }
michael@0 287 memset(entropy, 0, sizeof(entropy));
michael@0 288 memset(buf, 0, sizeof(buf));
michael@0 289 return 0;
michael@0 290 }
michael@0 291 #endif
michael@0 292
michael@0 293 #ifndef WIN32
michael@0 294 #define TRY_SEED_URANDOM
michael@0 295 static int
michael@0 296 arc4_seed_urandom(void)
michael@0 297 {
michael@0 298 /* This is adapted from Tor's crypto_seed_rng() */
michael@0 299 static const char *filenames[] = {
michael@0 300 "/dev/srandom", "/dev/urandom", "/dev/random", NULL
michael@0 301 };
michael@0 302 unsigned char buf[ADD_ENTROPY];
michael@0 303 int fd, i;
michael@0 304 size_t n;
michael@0 305
michael@0 306 for (i = 0; filenames[i]; ++i) {
michael@0 307 fd = evutil_open_closeonexec(filenames[i], O_RDONLY, 0);
michael@0 308 if (fd<0)
michael@0 309 continue;
michael@0 310 n = read_all(fd, buf, sizeof(buf));
michael@0 311 close(fd);
michael@0 312 if (n != sizeof(buf))
michael@0 313 return -1;
michael@0 314 arc4_addrandom(buf, sizeof(buf));
michael@0 315 memset(buf, 0, sizeof(buf));
michael@0 316 arc4_seeded_ok = 1;
michael@0 317 return 0;
michael@0 318 }
michael@0 319
michael@0 320 return -1;
michael@0 321 }
michael@0 322 #endif
michael@0 323
michael@0 324 static int
michael@0 325 arc4_seed(void)
michael@0 326 {
michael@0 327 int ok = 0;
michael@0 328 /* We try every method that might work, and don't give up even if one
michael@0 329 * does seem to work. There's no real harm in over-seeding, and if
michael@0 330 * one of these sources turns out to be broken, that would be bad. */
michael@0 331 #ifdef TRY_SEED_WIN32
michael@0 332 if (0 == arc4_seed_win32())
michael@0 333 ok = 1;
michael@0 334 #endif
michael@0 335 #ifdef TRY_SEED_URANDOM
michael@0 336 if (0 == arc4_seed_urandom())
michael@0 337 ok = 1;
michael@0 338 #endif
michael@0 339 #ifdef TRY_SEED_PROC_SYS_KERNEL_RANDOM_UUID
michael@0 340 if (0 == arc4_seed_proc_sys_kernel_random_uuid())
michael@0 341 ok = 1;
michael@0 342 #endif
michael@0 343 #ifdef TRY_SEED_SYSCTL_LINUX
michael@0 344 /* Apparently Linux is deprecating sysctl, and spewing warning
michael@0 345 * messages when you try to use it. */
michael@0 346 if (!ok && 0 == arc4_seed_sysctl_linux())
michael@0 347 ok = 1;
michael@0 348 #endif
michael@0 349 #ifdef TRY_SEED_SYSCTL_BSD
michael@0 350 if (0 == arc4_seed_sysctl_bsd())
michael@0 351 ok = 1;
michael@0 352 #endif
michael@0 353 return ok ? 0 : -1;
michael@0 354 }
michael@0 355
michael@0 356 static int
michael@0 357 arc4_stir(void)
michael@0 358 {
michael@0 359 int i;
michael@0 360
michael@0 361 if (!rs_initialized) {
michael@0 362 arc4_init();
michael@0 363 rs_initialized = 1;
michael@0 364 }
michael@0 365
michael@0 366 arc4_seed();
michael@0 367 if (!arc4_seeded_ok)
michael@0 368 return -1;
michael@0 369
michael@0 370 /*
michael@0 371 * Discard early keystream, as per recommendations in
michael@0 372 * "Weaknesses in the Key Scheduling Algorithm of RC4" by
michael@0 373 * Scott Fluhrer, Itsik Mantin, and Adi Shamir.
michael@0 374 * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
michael@0 375 *
michael@0 376 * Ilya Mironov's "(Not So) Random Shuffles of RC4" suggests that
michael@0 377 * we drop at least 2*256 bytes, with 12*256 as a conservative
michael@0 378 * value.
michael@0 379 *
michael@0 380 * RFC4345 says to drop 6*256.
michael@0 381 *
michael@0 382 * At least some versions of this code drop 4*256, in a mistaken
michael@0 383 * belief that "words" in the Fluhrer/Mantin/Shamir paper refers
michael@0 384 * to processor words.
michael@0 385 *
michael@0 386 * We add another sect to the cargo cult, and choose 12*256.
michael@0 387 */
michael@0 388 for (i = 0; i < 12*256; i++)
michael@0 389 (void)arc4_getbyte();
michael@0 390 arc4_count = BYTES_BEFORE_RESEED;
michael@0 391
michael@0 392 return 0;
michael@0 393 }
michael@0 394
michael@0 395
michael@0 396 static void
michael@0 397 arc4_stir_if_needed(void)
michael@0 398 {
michael@0 399 pid_t pid = getpid();
michael@0 400
michael@0 401 if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid)
michael@0 402 {
michael@0 403 arc4_stir_pid = pid;
michael@0 404 arc4_stir();
michael@0 405 }
michael@0 406 }
michael@0 407
michael@0 408 static inline unsigned char
michael@0 409 arc4_getbyte(void)
michael@0 410 {
michael@0 411 unsigned char si, sj;
michael@0 412
michael@0 413 rs.i = (rs.i + 1);
michael@0 414 si = rs.s[rs.i];
michael@0 415 rs.j = (rs.j + si);
michael@0 416 sj = rs.s[rs.j];
michael@0 417 rs.s[rs.i] = sj;
michael@0 418 rs.s[rs.j] = si;
michael@0 419 return (rs.s[(si + sj) & 0xff]);
michael@0 420 }
michael@0 421
michael@0 422 static inline unsigned int
michael@0 423 arc4_getword(void)
michael@0 424 {
michael@0 425 unsigned int val;
michael@0 426
michael@0 427 val = arc4_getbyte() << 24;
michael@0 428 val |= arc4_getbyte() << 16;
michael@0 429 val |= arc4_getbyte() << 8;
michael@0 430 val |= arc4_getbyte();
michael@0 431
michael@0 432 return val;
michael@0 433 }
michael@0 434
michael@0 435 #ifndef ARC4RANDOM_NOSTIR
michael@0 436 ARC4RANDOM_EXPORT int
michael@0 437 arc4random_stir(void)
michael@0 438 {
michael@0 439 int val;
michael@0 440 _ARC4_LOCK();
michael@0 441 val = arc4_stir();
michael@0 442 _ARC4_UNLOCK();
michael@0 443 return val;
michael@0 444 }
michael@0 445 #endif
michael@0 446
michael@0 447 #ifndef ARC4RANDOM_NOADDRANDOM
michael@0 448 ARC4RANDOM_EXPORT void
michael@0 449 arc4random_addrandom(const unsigned char *dat, int datlen)
michael@0 450 {
michael@0 451 int j;
michael@0 452 _ARC4_LOCK();
michael@0 453 if (!rs_initialized)
michael@0 454 arc4_stir();
michael@0 455 for (j = 0; j < datlen; j += 256) {
michael@0 456 /* arc4_addrandom() ignores all but the first 256 bytes of
michael@0 457 * its input. We want to make sure to look at ALL the
michael@0 458 * data in 'dat', just in case the user is doing something
michael@0 459 * crazy like passing us all the files in /var/log. */
michael@0 460 arc4_addrandom(dat + j, datlen - j);
michael@0 461 }
michael@0 462 _ARC4_UNLOCK();
michael@0 463 }
michael@0 464 #endif
michael@0 465
michael@0 466 #ifndef ARC4RANDOM_NORANDOM
michael@0 467 ARC4RANDOM_EXPORT ARC4RANDOM_UINT32
michael@0 468 arc4random(void)
michael@0 469 {
michael@0 470 ARC4RANDOM_UINT32 val;
michael@0 471 _ARC4_LOCK();
michael@0 472 arc4_count -= 4;
michael@0 473 arc4_stir_if_needed();
michael@0 474 val = arc4_getword();
michael@0 475 _ARC4_UNLOCK();
michael@0 476 return val;
michael@0 477 }
michael@0 478 #endif
michael@0 479
michael@0 480 ARC4RANDOM_EXPORT void
michael@0 481 arc4random_buf(void *_buf, size_t n)
michael@0 482 {
michael@0 483 unsigned char *buf = _buf;
michael@0 484 _ARC4_LOCK();
michael@0 485 arc4_stir_if_needed();
michael@0 486 while (n--) {
michael@0 487 if (--arc4_count <= 0)
michael@0 488 arc4_stir();
michael@0 489 buf[n] = arc4_getbyte();
michael@0 490 }
michael@0 491 _ARC4_UNLOCK();
michael@0 492 }
michael@0 493
michael@0 494 #ifndef ARC4RANDOM_NOUNIFORM
michael@0 495 /*
michael@0 496 * Calculate a uniformly distributed random number less than upper_bound
michael@0 497 * avoiding "modulo bias".
michael@0 498 *
michael@0 499 * Uniformity is achieved by generating new random numbers until the one
michael@0 500 * returned is outside the range [0, 2**32 % upper_bound). This
michael@0 501 * guarantees the selected random number will be inside
michael@0 502 * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
michael@0 503 * after reduction modulo upper_bound.
michael@0 504 */
michael@0 505 ARC4RANDOM_EXPORT unsigned int
michael@0 506 arc4random_uniform(unsigned int upper_bound)
michael@0 507 {
michael@0 508 ARC4RANDOM_UINT32 r, min;
michael@0 509
michael@0 510 if (upper_bound < 2)
michael@0 511 return 0;
michael@0 512
michael@0 513 #if (UINT_MAX > 0xffffffffUL)
michael@0 514 min = 0x100000000UL % upper_bound;
michael@0 515 #else
michael@0 516 /* Calculate (2**32 % upper_bound) avoiding 64-bit math */
michael@0 517 if (upper_bound > 0x80000000)
michael@0 518 min = 1 + ~upper_bound; /* 2**32 - upper_bound */
michael@0 519 else {
michael@0 520 /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
michael@0 521 min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound;
michael@0 522 }
michael@0 523 #endif
michael@0 524
michael@0 525 /*
michael@0 526 * This could theoretically loop forever but each retry has
michael@0 527 * p > 0.5 (worst case, usually far better) of selecting a
michael@0 528 * number inside the range we need, so it should rarely need
michael@0 529 * to re-roll.
michael@0 530 */
michael@0 531 for (;;) {
michael@0 532 r = arc4random();
michael@0 533 if (r >= min)
michael@0 534 break;
michael@0 535 }
michael@0 536
michael@0 537 return r % upper_bound;
michael@0 538 }
michael@0 539 #endif

mercurial