michael@0: /* Portable arc4random.c based on arc4random.c from OpenBSD. michael@0: * Portable version by Chris Davis, adapted for Libevent by Nick Mathewson michael@0: * Copyright (c) 2010 Chris Davis, Niels Provos, and Nick Mathewson michael@0: * Copyright (c) 2010-2012 Niels Provos and Nick Mathewson michael@0: * michael@0: * Note that in Libevent, this file isn't compiled directly. Instead, michael@0: * it's included from evutil_rand.c michael@0: */ michael@0: michael@0: /* michael@0: * Copyright (c) 1996, David Mazieres michael@0: * Copyright (c) 2008, Damien Miller michael@0: * michael@0: * Permission to use, copy, modify, and distribute this software for any michael@0: * purpose with or without fee is hereby granted, provided that the above michael@0: * copyright notice and this permission notice appear in all copies. michael@0: * michael@0: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES michael@0: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF michael@0: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR michael@0: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES michael@0: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN michael@0: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF michael@0: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. michael@0: */ michael@0: michael@0: /* michael@0: * Arc4 random number generator for OpenBSD. michael@0: * michael@0: * This code is derived from section 17.1 of Applied Cryptography, michael@0: * second edition, which describes a stream cipher allegedly michael@0: * compatible with RSA Labs "RC4" cipher (the actual description of michael@0: * which is a trade secret). The same algorithm is used as a stream michael@0: * cipher called "arcfour" in Tatu Ylonen's ssh package. michael@0: * michael@0: * Here the stream cipher has been modified always to include the time michael@0: * when initializing the state. That makes it impossible to michael@0: * regenerate the same random sequence twice, so this can't be used michael@0: * for encryption, but will generate good random numbers. michael@0: * michael@0: * RC4 is a registered trademark of RSA Laboratories. michael@0: */ michael@0: michael@0: #ifndef ARC4RANDOM_EXPORT michael@0: #define ARC4RANDOM_EXPORT michael@0: #endif michael@0: michael@0: #ifndef ARC4RANDOM_UINT32 michael@0: #define ARC4RANDOM_UINT32 uint32_t michael@0: #endif michael@0: michael@0: #ifndef ARC4RANDOM_NO_INCLUDES michael@0: #ifdef WIN32 michael@0: #include michael@0: #include michael@0: #else michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #ifdef _EVENT_HAVE_SYS_SYSCTL_H michael@0: #include michael@0: #endif michael@0: #endif michael@0: #include michael@0: #include michael@0: #include michael@0: #endif michael@0: michael@0: /* Add platform entropy 32 bytes (256 bits) at a time. */ michael@0: #define ADD_ENTROPY 32 michael@0: michael@0: /* Re-seed from the platform RNG after generating this many bytes. */ michael@0: #define BYTES_BEFORE_RESEED 1600000 michael@0: michael@0: struct arc4_stream { michael@0: unsigned char i; michael@0: unsigned char j; michael@0: unsigned char s[256]; michael@0: }; michael@0: michael@0: #ifdef WIN32 michael@0: #define getpid _getpid michael@0: #define pid_t int michael@0: #endif michael@0: michael@0: static int rs_initialized; michael@0: static struct arc4_stream rs; michael@0: static pid_t arc4_stir_pid; michael@0: static int arc4_count; michael@0: static int arc4_seeded_ok; michael@0: michael@0: static inline unsigned char arc4_getbyte(void); michael@0: michael@0: static inline void michael@0: arc4_init(void) michael@0: { michael@0: int n; michael@0: michael@0: for (n = 0; n < 256; n++) michael@0: rs.s[n] = n; michael@0: rs.i = 0; michael@0: rs.j = 0; michael@0: } michael@0: michael@0: static inline void michael@0: arc4_addrandom(const unsigned char *dat, int datlen) michael@0: { michael@0: int n; michael@0: unsigned char si; michael@0: michael@0: rs.i--; michael@0: for (n = 0; n < 256; n++) { michael@0: rs.i = (rs.i + 1); michael@0: si = rs.s[rs.i]; michael@0: rs.j = (rs.j + si + dat[n % datlen]); michael@0: rs.s[rs.i] = rs.s[rs.j]; michael@0: rs.s[rs.j] = si; michael@0: } michael@0: rs.j = rs.i; michael@0: } michael@0: michael@0: #ifndef WIN32 michael@0: static ssize_t michael@0: read_all(int fd, unsigned char *buf, size_t count) michael@0: { michael@0: size_t numread = 0; michael@0: ssize_t result; michael@0: michael@0: while (numread < count) { michael@0: result = read(fd, buf+numread, count-numread); michael@0: if (result<0) michael@0: return -1; michael@0: else if (result == 0) michael@0: break; michael@0: numread += result; michael@0: } michael@0: michael@0: return (ssize_t)numread; michael@0: } michael@0: #endif michael@0: michael@0: #ifdef WIN32 michael@0: #define TRY_SEED_WIN32 michael@0: static int michael@0: arc4_seed_win32(void) michael@0: { michael@0: /* This is adapted from Tor's crypto_seed_rng() */ michael@0: static int provider_set = 0; michael@0: static HCRYPTPROV provider; michael@0: unsigned char buf[ADD_ENTROPY]; michael@0: michael@0: if (!provider_set) { michael@0: if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, michael@0: CRYPT_VERIFYCONTEXT)) { michael@0: if (GetLastError() != (DWORD)NTE_BAD_KEYSET) michael@0: return -1; michael@0: } michael@0: provider_set = 1; michael@0: } michael@0: if (!CryptGenRandom(provider, sizeof(buf), buf)) michael@0: return -1; michael@0: arc4_addrandom(buf, sizeof(buf)); michael@0: memset(buf, 0, sizeof(buf)); michael@0: arc4_seeded_ok = 1; michael@0: return 0; michael@0: } michael@0: #endif michael@0: michael@0: #if defined(_EVENT_HAVE_SYS_SYSCTL_H) && defined(_EVENT_HAVE_SYSCTL) michael@0: #if _EVENT_HAVE_DECL_CTL_KERN && _EVENT_HAVE_DECL_KERN_RANDOM && _EVENT_HAVE_DECL_RANDOM_UUID michael@0: #define TRY_SEED_SYSCTL_LINUX michael@0: static int michael@0: arc4_seed_sysctl_linux(void) michael@0: { michael@0: /* Based on code by William Ahern, this function tries to use the michael@0: * RANDOM_UUID sysctl to get entropy from the kernel. This can work michael@0: * even if /dev/urandom is inaccessible for some reason (e.g., we're michael@0: * running in a chroot). */ michael@0: int mib[] = { CTL_KERN, KERN_RANDOM, RANDOM_UUID }; michael@0: unsigned char buf[ADD_ENTROPY]; michael@0: size_t len, n; michael@0: unsigned i; michael@0: int any_set; michael@0: michael@0: memset(buf, 0, sizeof(buf)); michael@0: michael@0: for (len = 0; len < sizeof(buf); len += n) { michael@0: n = sizeof(buf) - len; michael@0: michael@0: if (0 != sysctl(mib, 3, &buf[len], &n, NULL, 0)) michael@0: return -1; michael@0: } michael@0: /* make sure that the buffer actually got set. */ michael@0: for (i=0,any_set=0; i sizeof(buf)) michael@0: n = len - sizeof(buf); michael@0: if (sysctl(mib, 2, &buf[len], &n, NULL, 0) == -1) michael@0: return -1; michael@0: } michael@0: } michael@0: /* make sure that the buffer actually got set. */ michael@0: for (i=any_set=0; i 0xffffffffUL) michael@0: min = 0x100000000UL % upper_bound; michael@0: #else michael@0: /* Calculate (2**32 % upper_bound) avoiding 64-bit math */ michael@0: if (upper_bound > 0x80000000) michael@0: min = 1 + ~upper_bound; /* 2**32 - upper_bound */ michael@0: else { michael@0: /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */ michael@0: min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound; michael@0: } michael@0: #endif michael@0: michael@0: /* michael@0: * This could theoretically loop forever but each retry has michael@0: * p > 0.5 (worst case, usually far better) of selecting a michael@0: * number inside the range we need, so it should rarely need michael@0: * to re-roll. michael@0: */ michael@0: for (;;) { michael@0: r = arc4random(); michael@0: if (r >= min) michael@0: break; michael@0: } michael@0: michael@0: return r % upper_bound; michael@0: } michael@0: #endif