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