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