Coverage Report

Created: 2023-09-25 06:52

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