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