LCOV - code coverage report
Current view: top level - ipc/chromium/src/third_party/libevent - arc4random.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 121 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 12 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : #define ADD_ENTROPY 32
      73             : 
      74             : /* Re-seed from the platform RNG after generating this many bytes. */
      75             : #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           0 : arc4_init(void)
      98             : {
      99             :         int     n;
     100             : 
     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           0 : arc4_addrandom(const unsigned char *dat, int datlen)
     109             : {
     110             :         int     n;
     111             :         unsigned char si;
     112             : 
     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             :         }
     121           0 :         rs.j = rs.i;
     122           0 : }
     123             : 
     124             : #ifndef _WIN32
     125             : static ssize_t
     126           0 : read_all(int fd, unsigned char *buf, size_t count)
     127             : {
     128           0 :         size_t numread = 0;
     129             :         ssize_t result;
     130             : 
     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             :         }
     139             : 
     140           0 :         return (ssize_t)numread;
     141             : }
     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             : {
     177             :         /* Based on code by William Ahern, this function tries to use the
     178             :          * RANDOM_UUID sysctl to get entropy from the kernel.  This can work
     179             :          * even if /dev/urandom is inaccessible for some reason (e.g., we're
     180             :          * running in a chroot). */
     181             :         int mib[] = { CTL_KERN, KERN_RANDOM, RANDOM_UUID };
     182             :         unsigned char buf[ADD_ENTROPY];
     183             :         size_t len, n;
     184             :         unsigned i;
     185             :         int any_set;
     186             : 
     187             :         memset(buf, 0, sizeof(buf));
     188             : 
     189             :         for (len = 0; len < sizeof(buf); len += n) {
     190             :                 n = sizeof(buf) - len;
     191             : 
     192             :                 if (0 != sysctl(mib, 3, &buf[len], &n, NULL, 0))
     193             :                         return -1;
     194             :         }
     195             :         /* make sure that the buffer actually got set. */
     196             :         for (i=0,any_set=0; i<sizeof(buf); ++i) {
     197             :                 any_set |= buf[i];
     198             :         }
     199             :         if (!any_set)
     200             :                 return -1;
     201             : 
     202             :         arc4_addrandom(buf, sizeof(buf));
     203             :         evutil_memclear_(buf, sizeof(buf));
     204             :         arc4_seeded_ok = 1;
     205             :         return 0;
     206             : }
     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           0 : arc4_seed_proc_sys_kernel_random_uuid(void)
     254             : {
     255             :         /* Occasionally, somebody will make /proc/sys accessible in a chroot,
     256             :          * but not /dev/urandom.  Let's try /proc/sys/kernel/random/uuid.
     257             :          * Its format is stupid, so we need to decode it from hex.
     258             :          */
     259             :         int fd;
     260             :         char buf[128];
     261             :         unsigned char entropy[64];
     262             :         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             :                                 } else {
     278           0 :                                         entropy[nybbles/2] |= nyb<<4;
     279             :                                 }
     280           0 :                                 ++nybbles;
     281             :                         }
     282             :                 }
     283           0 :                 if (nybbles < 2)
     284           0 :                         return -1;
     285           0 :                 arc4_addrandom(entropy, nybbles/2);
     286           0 :                 bytes += nybbles/2;
     287             :         }
     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             : }
     293             : #endif
     294             : 
     295             : #ifndef _WIN32
     296             : #define TRY_SEED_URANDOM
     297             : static char *arc4random_urandom_filename = NULL;
     298             : 
     299           0 : static int arc4_seed_urandom_helper_(const char *fname)
     300             : {
     301             :         unsigned char buf[ADD_ENTROPY];
     302             :         int fd;
     303             :         size_t n;
     304             : 
     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             : }
     317             : 
     318             : static int
     319           0 : arc4_seed_urandom(void)
     320             : {
     321             :         /* This is adapted from Tor's crypto_seed_rng() */
     322             :         static const char *filenames[] = {
     323             :                 "/dev/srandom", "/dev/urandom", "/dev/random", NULL
     324             :         };
     325             :         int i;
     326           0 :         if (arc4random_urandom_filename)
     327           0 :                 return arc4_seed_urandom_helper_(arc4random_urandom_filename);
     328             : 
     329           0 :         for (i = 0; filenames[i]; ++i) {
     330           0 :                 if (arc4_seed_urandom_helper_(filenames[i]) == 0) {
     331           0 :                         return 0;
     332             :                 }
     333             :         }
     334             : 
     335           0 :         return -1;
     336             : }
     337             : #endif
     338             : 
     339             : static int
     340           0 : arc4_seed(void)
     341             : {
     342           0 :         int ok = 0;
     343             :         /* We try every method that might work, and don't give up even if one
     344             :          * does seem to work.  There's no real harm in over-seeding, and if
     345             :          * 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             : #endif
     354             : #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             : #endif
     359             : #ifdef TRY_SEED_SYSCTL_LINUX
     360             :         /* Apparently Linux is deprecating sysctl, and spewing warning
     361             :          * messages when you try to use it. */
     362             :         if (!ok && 0 == arc4_seed_sysctl_linux())
     363             :                 ok = 1;
     364             : #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             : }
     371             : 
     372             : static int
     373           0 : arc4_stir(void)
     374             : {
     375             :         int     i;
     376             : 
     377           0 :         if (!rs_initialized) {
     378           0 :                 arc4_init();
     379           0 :                 rs_initialized = 1;
     380             :         }
     381             : 
     382           0 :         arc4_seed();
     383           0 :         if (!arc4_seeded_ok)
     384           0 :                 return -1;
     385             : 
     386             :         /*
     387             :          * Discard early keystream, as per recommendations in
     388             :          * "Weaknesses in the Key Scheduling Algorithm of RC4" by
     389             :          * Scott Fluhrer, Itsik Mantin, and Adi Shamir.
     390             :          * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
     391             :          *
     392             :          * Ilya Mironov's "(Not So) Random Shuffles of RC4" suggests that
     393             :          * we drop at least 2*256 bytes, with 12*256 as a conservative
     394             :          * value.
     395             :          *
     396             :          * RFC4345 says to drop 6*256.
     397             :          *
     398             :          * At least some versions of this code drop 4*256, in a mistaken
     399             :          * belief that "words" in the Fluhrer/Mantin/Shamir paper refers
     400             :          * to processor words.
     401             :          *
     402             :          * We add another sect to the cargo cult, and choose 12*256.
     403             :          */
     404           0 :         for (i = 0; i < 12*256; i++)
     405           0 :                 (void)arc4_getbyte();
     406             : 
     407           0 :         arc4_count = BYTES_BEFORE_RESEED;
     408             : 
     409           0 :         return 0;
     410             : }
     411             : 
     412             : 
     413             : static void
     414           0 : arc4_stir_if_needed(void)
     415             : {
     416           0 :         pid_t pid = getpid();
     417             : 
     418           0 :         if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid)
     419             :         {
     420           0 :                 arc4_stir_pid = pid;
     421           0 :                 arc4_stir();
     422             :         }
     423           0 : }
     424             : 
     425             : static inline unsigned char
     426           0 : arc4_getbyte(void)
     427             : {
     428             :         unsigned char si, sj;
     429             : 
     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             : }
     438             : 
     439             : static inline unsigned int
     440             : arc4_getword(void)
     441             : {
     442             :         unsigned int val;
     443             : 
     444             :         val = arc4_getbyte() << 24;
     445             :         val |= arc4_getbyte() << 16;
     446             :         val |= arc4_getbyte() << 8;
     447             :         val |= arc4_getbyte();
     448             : 
     449             :         return val;
     450             : }
     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           0 : arc4random_addrandom(const unsigned char *dat, int datlen)
     467             : {
     468             :         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             :                 /* arc4_addrandom() ignores all but the first 256 bytes of
     474             :                  * its input.  We want to make sure to look at ALL the
     475             :                  * data in 'dat', just in case the user is doing something
     476             :                  * crazy like passing us all the files in /var/log. */
     477           0 :                 arc4_addrandom(dat + j, datlen - j);
     478             :         }
     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           0 : arc4random_buf(void *buf_, size_t n)
     499             : {
     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             :         }
     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

Generated by: LCOV version 1.13