root/opal/mca/event/libevent2022/libevent/arc4random.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. arc4_init
  2. arc4_addrandom
  3. read_all
  4. arc4_seed_win32
  5. arc4_seed_sysctl_linux
  6. arc4_seed_sysctl_bsd
  7. arc4_seed_proc_sys_kernel_random_uuid
  8. arc4_seed_urandom_helper_
  9. arc4_seed_urandom
  10. arc4_seed
  11. arc4_stir
  12. arc4_stir_if_needed
  13. arc4_getbyte
  14. arc4_getword
  15. arc4random_stir
  16. arc4random_addrandom
  17. arc4random
  18. arc4random_buf
  19. arc4random_uniform

   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         evutil_memclear_(buf, 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         evutil_memclear_(buf, 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         evutil_memclear_(buf, 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         evutil_memclear_(entropy, sizeof(entropy));
 288         evutil_memclear_(buf, sizeof(buf));
 289         arc4_seeded_ok = 1;
 290         return 0;
 291 }
 292 #endif
 293 
 294 #ifndef WIN32
 295 #define TRY_SEED_URANDOM
 296 static char *arc4random_urandom_filename = NULL;
 297 
 298 static int arc4_seed_urandom_helper_(const char *fname)
 299 {
 300         unsigned char buf[ADD_ENTROPY];
 301         int fd;
 302         size_t n;
 303 
 304         fd = evutil_open_closeonexec(fname, O_RDONLY, 0);
 305         if (fd<0)
 306                 return -1;
 307         n = read_all(fd, buf, sizeof(buf));
 308         close(fd);
 309         if (n != sizeof(buf))
 310                 return -1;
 311         arc4_addrandom(buf, sizeof(buf));
 312         evutil_memclear_(buf, sizeof(buf));
 313         arc4_seeded_ok = 1;
 314         return 0;
 315 }
 316 
 317 static int
 318 arc4_seed_urandom(void)
 319 {
 320         /* This is adapted from Tor's crypto_seed_rng() */
 321         static const char *filenames[] = {
 322                 "/dev/srandom", "/dev/urandom", "/dev/random", NULL
 323         };
 324         int i;
 325         if (arc4random_urandom_filename)
 326                 return arc4_seed_urandom_helper_(arc4random_urandom_filename);
 327 
 328         for (i = 0; filenames[i]; ++i) {
 329                 if (arc4_seed_urandom_helper_(filenames[i]) == 0) {
 330                         return 0;
 331                 }
 332         }
 333 
 334         return -1;
 335 }
 336 #endif
 337 
 338 static int
 339 arc4_seed(void)
 340 {
 341         int ok = 0;
 342         /* We try every method that might work, and don't give up even if one
 343          * does seem to work.  There's no real harm in over-seeding, and if
 344          * one of these sources turns out to be broken, that would be bad. */
 345 #ifdef TRY_SEED_WIN32
 346         if (0 == arc4_seed_win32())
 347                 ok = 1;
 348 #endif
 349 #ifdef TRY_SEED_URANDOM
 350         if (0 == arc4_seed_urandom())
 351                 ok = 1;
 352 #endif
 353 #ifdef TRY_SEED_PROC_SYS_KERNEL_RANDOM_UUID
 354         if (arc4random_urandom_filename == NULL &&
 355             0 == arc4_seed_proc_sys_kernel_random_uuid())
 356                 ok = 1;
 357 #endif
 358 #ifdef TRY_SEED_SYSCTL_LINUX
 359         /* Apparently Linux is deprecating sysctl, and spewing warning
 360          * messages when you try to use it. */
 361         if (!ok && 0 == arc4_seed_sysctl_linux())
 362                 ok = 1;
 363 #endif
 364 #ifdef TRY_SEED_SYSCTL_BSD
 365         if (0 == arc4_seed_sysctl_bsd())
 366                 ok = 1;
 367 #endif
 368         return ok ? 0 : -1;
 369 }
 370 
 371 static int
 372 arc4_stir(void)
 373 {
 374         int     i;
 375 
 376         if (!rs_initialized) {
 377                 arc4_init();
 378                 rs_initialized = 1;
 379         }
 380 
 381         arc4_seed();
 382         if (!arc4_seeded_ok)
 383                 return -1;
 384 
 385         /*
 386          * Discard early keystream, as per recommendations in
 387          * "Weaknesses in the Key Scheduling Algorithm of RC4" by
 388          * Scott Fluhrer, Itsik Mantin, and Adi Shamir.
 389          * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
 390          *
 391          * Ilya Mironov's "(Not So) Random Shuffles of RC4" suggests that
 392          * we drop at least 2*256 bytes, with 12*256 as a conservative
 393          * value.
 394          *
 395          * RFC4345 says to drop 6*256.
 396          *
 397          * At least some versions of this code drop 4*256, in a mistaken
 398          * belief that "words" in the Fluhrer/Mantin/Shamir paper refers
 399          * to processor words.
 400          *
 401          * We add another sect to the cargo cult, and choose 12*256.
 402          */
 403         for (i = 0; i < 12*256; i++)
 404                 (void)arc4_getbyte();
 405 
 406         arc4_count = BYTES_BEFORE_RESEED;
 407 
 408         return 0;
 409 }
 410 
 411 
 412 static void
 413 arc4_stir_if_needed(void)
 414 {
 415         pid_t pid = getpid();
 416 
 417         if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid)
 418         {
 419                 arc4_stir_pid = pid;
 420                 arc4_stir();
 421         }
 422 }
 423 
 424 static inline unsigned char
 425 arc4_getbyte(void)
 426 {
 427         unsigned char si, sj;
 428 
 429         rs.i = (rs.i + 1);
 430         si = rs.s[rs.i];
 431         rs.j = (rs.j + si);
 432         sj = rs.s[rs.j];
 433         rs.s[rs.i] = sj;
 434         rs.s[rs.j] = si;
 435         return (rs.s[(si + sj) & 0xff]);
 436 }
 437 
 438 static inline unsigned int
 439 arc4_getword(void)
 440 {
 441         unsigned int val;
 442 
 443         val = arc4_getbyte() << 24;
 444         val |= arc4_getbyte() << 16;
 445         val |= arc4_getbyte() << 8;
 446         val |= arc4_getbyte();
 447 
 448         return val;
 449 }
 450 
 451 #ifndef ARC4RANDOM_NOSTIR
 452 ARC4RANDOM_EXPORT int
 453 arc4random_stir(void)
 454 {
 455         int val;
 456         _ARC4_LOCK();
 457         val = arc4_stir();
 458         _ARC4_UNLOCK();
 459         return val;
 460 }
 461 #endif
 462 
 463 /****    OMPI CHANGE    ****/
 464 /* We don't use arc4random_addrandom anywhere,
 465  * and some OS's don't like it - so just don't
 466  * build the darn thing */
 467 #if 0
 468 #ifndef ARC4RANDOM_NOADDRANDOM
 469 ARC4RANDOM_EXPORT void
 470 arc4random_addrandom(const unsigned char *dat, int datlen)
 471 {
 472         int j;
 473         _ARC4_LOCK();
 474         if (!rs_initialized)
 475                 arc4_stir();
 476         for (j = 0; j < datlen; j += 256) {
 477                 /* arc4_addrandom() ignores all but the first 256 bytes of
 478                  * its input.  We want to make sure to look at ALL the
 479                  * data in 'dat', just in case the user is doing something
 480                  * crazy like passing us all the files in /var/log. */
 481                 arc4_addrandom(dat + j, datlen - j);
 482         }
 483         _ARC4_UNLOCK();
 484 }
 485 #endif
 486 #endif
 487 
 488 #ifndef ARC4RANDOM_NORANDOM
 489 ARC4RANDOM_EXPORT ARC4RANDOM_UINT32
 490 arc4random(void)
 491 {
 492         ARC4RANDOM_UINT32 val;
 493         _ARC4_LOCK();
 494         arc4_count -= 4;
 495         arc4_stir_if_needed();
 496         val = arc4_getword();
 497         _ARC4_UNLOCK();
 498         return val;
 499 }
 500 #endif
 501 
 502 ARC4RANDOM_EXPORT void
 503 arc4random_buf(void *_buf, size_t n)
 504 {
 505         unsigned char *buf = _buf;
 506         _ARC4_LOCK();
 507         arc4_stir_if_needed();
 508         while (n--) {
 509                 if (--arc4_count <= 0)
 510                         arc4_stir();
 511                 buf[n] = arc4_getbyte();
 512         }
 513         _ARC4_UNLOCK();
 514 }
 515 
 516 #ifndef ARC4RANDOM_NOUNIFORM
 517 /*
 518  * Calculate a uniformly distributed random number less than upper_bound
 519  * avoiding "modulo bias".
 520  *
 521  * Uniformity is achieved by generating new random numbers until the one
 522  * returned is outside the range [0, 2**32 % upper_bound).  This
 523  * guarantees the selected random number will be inside
 524  * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
 525  * after reduction modulo upper_bound.
 526  */
 527 ARC4RANDOM_EXPORT unsigned int
 528 arc4random_uniform(unsigned int upper_bound)
 529 {
 530         ARC4RANDOM_UINT32 r, min;
 531 
 532         if (upper_bound < 2)
 533                 return 0;
 534 
 535 #if (UINT_MAX > 0xffffffffUL)
 536         min = 0x100000000UL % upper_bound;
 537 #else
 538         /* Calculate (2**32 % upper_bound) avoiding 64-bit math */
 539         if (upper_bound > 0x80000000)
 540                 min = 1 + ~upper_bound;         /* 2**32 - upper_bound */
 541         else {
 542                 /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
 543                 min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound;
 544         }
 545 #endif
 546 
 547         /*
 548          * This could theoretically loop forever but each retry has
 549          * p > 0.5 (worst case, usually far better) of selecting a
 550          * number inside the range we need, so it should rarely need
 551          * to re-roll.
 552          */
 553         for (;;) {
 554                 r = arc4random();
 555                 if (r >= min)
 556                         break;
 557         }
 558 
 559         return r % upper_bound;
 560 }
 561 #endif

/* [<][>][^][v][top][bottom][index][help] */