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