Coverage Report

Created: 2018-08-29 13:53

/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