1c0b48470SDavid Schultz /* $OpenBSD: arc4random.c,v 1.22 2010/12/22 08:23:42 otto Exp $ */ 2c0b48470SDavid Schultz 383a03b38SAndrey A. Chernov /* 4860c4e58SAndrey A. Chernov * Copyright (c) 1996, David Mazieres <dm@uun.org> 5860c4e58SAndrey A. Chernov * Copyright (c) 2008, Damien Miller <djm@openbsd.org> 683a03b38SAndrey A. Chernov * 7860c4e58SAndrey A. Chernov * Permission to use, copy, modify, and distribute this software for any 8860c4e58SAndrey A. Chernov * purpose with or without fee is hereby granted, provided that the above 9860c4e58SAndrey A. Chernov * copyright notice and this permission notice appear in all copies. 10860c4e58SAndrey A. Chernov * 11860c4e58SAndrey A. Chernov * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12860c4e58SAndrey A. Chernov * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13860c4e58SAndrey A. Chernov * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14860c4e58SAndrey A. Chernov * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15860c4e58SAndrey A. Chernov * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16860c4e58SAndrey A. Chernov * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17860c4e58SAndrey A. Chernov * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1883a03b38SAndrey A. Chernov */ 1983a03b38SAndrey A. Chernov 2083a03b38SAndrey A. Chernov /* 21860c4e58SAndrey A. Chernov * Arc4 random number generator for OpenBSD. 22860c4e58SAndrey A. Chernov * 2383a03b38SAndrey A. Chernov * This code is derived from section 17.1 of Applied Cryptography, 2483a03b38SAndrey A. Chernov * second edition, which describes a stream cipher allegedly 2583a03b38SAndrey A. Chernov * compatible with RSA Labs "RC4" cipher (the actual description of 2683a03b38SAndrey A. Chernov * which is a trade secret). The same algorithm is used as a stream 2783a03b38SAndrey A. Chernov * cipher called "arcfour" in Tatu Ylonen's ssh package. 2883a03b38SAndrey A. Chernov * 2983a03b38SAndrey A. Chernov * RC4 is a registered trademark of RSA Laboratories. 3083a03b38SAndrey A. Chernov */ 3183a03b38SAndrey A. Chernov 32333fc21eSDavid E. O'Brien #include <sys/cdefs.h> 33333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 34333fc21eSDavid E. O'Brien 35d201fe46SDaniel Eischen #include "namespace.h" 3683a03b38SAndrey A. Chernov #include <fcntl.h> 37*7a0789b4SDavid Schultz #include <limits.h> 38*7a0789b4SDavid Schultz #include <stdlib.h> 3983a03b38SAndrey A. Chernov #include <unistd.h> 40*7a0789b4SDavid Schultz #include <sys/types.h> 41*7a0789b4SDavid Schultz #include <sys/param.h> 42*7a0789b4SDavid Schultz #include <sys/time.h> 435295209eSBrian Feldman #include <pthread.h> 445295209eSBrian Feldman 455295209eSBrian Feldman #include "libc_private.h" 46d201fe46SDaniel Eischen #include "un-namespace.h" 4783a03b38SAndrey A. Chernov 48c0b48470SDavid Schultz #ifdef __GNUC__ 49c0b48470SDavid Schultz #define inline __inline 50c0b48470SDavid Schultz #else /* !__GNUC__ */ 51c0b48470SDavid Schultz #define inline 52c0b48470SDavid Schultz #endif /* !__GNUC__ */ 53c0b48470SDavid Schultz 5483a03b38SAndrey A. Chernov struct arc4_stream { 5583a03b38SAndrey A. Chernov u_int8_t i; 5683a03b38SAndrey A. Chernov u_int8_t j; 5783a03b38SAndrey A. Chernov u_int8_t s[256]; 5883a03b38SAndrey A. Chernov }; 5983a03b38SAndrey A. Chernov 605295209eSBrian Feldman static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; 615295209eSBrian Feldman 624220467eSAndrey A. Chernov #define RANDOMDEV "/dev/random" 6389538e75SAndrey A. Chernov #define KEYSIZE 128 64c0b48470SDavid Schultz #define _ARC4_LOCK() \ 655295209eSBrian Feldman do { \ 665295209eSBrian Feldman if (__isthreaded) \ 675295209eSBrian Feldman _pthread_mutex_lock(&arc4random_mtx); \ 685295209eSBrian Feldman } while (0) 695295209eSBrian Feldman 70c0b48470SDavid Schultz #define _ARC4_UNLOCK() \ 715295209eSBrian Feldman do { \ 725295209eSBrian Feldman if (__isthreaded) \ 735295209eSBrian Feldman _pthread_mutex_unlock(&arc4random_mtx); \ 745295209eSBrian Feldman } while (0) 755295209eSBrian Feldman 765295209eSBrian Feldman static int rs_initialized; 77*7a0789b4SDavid Schultz static struct arc4_stream rs; 78*7a0789b4SDavid Schultz static pid_t arc4_stir_pid; 79f68412f9SAndrey A. Chernov static int arc4_count; 8083a03b38SAndrey A. Chernov 81860c4e58SAndrey A. Chernov static inline u_int8_t arc4_getbyte(void); 82860c4e58SAndrey A. Chernov static void arc4_stir(void); 8360ce8b0eSDavid Schultz 8483a03b38SAndrey A. Chernov static inline void 85860c4e58SAndrey A. Chernov arc4_init(void) 8683a03b38SAndrey A. Chernov { 8783a03b38SAndrey A. Chernov int n; 8883a03b38SAndrey A. Chernov 8983a03b38SAndrey A. Chernov for (n = 0; n < 256; n++) 90860c4e58SAndrey A. Chernov rs.s[n] = n; 91860c4e58SAndrey A. Chernov rs.i = 0; 92860c4e58SAndrey A. Chernov rs.j = 0; 9383a03b38SAndrey A. Chernov } 9483a03b38SAndrey A. Chernov 9583a03b38SAndrey A. Chernov static inline void 96860c4e58SAndrey A. Chernov arc4_addrandom(u_char *dat, int datlen) 9783a03b38SAndrey A. Chernov { 9883a03b38SAndrey A. Chernov int n; 9983a03b38SAndrey A. Chernov u_int8_t si; 10083a03b38SAndrey A. Chernov 101860c4e58SAndrey A. Chernov rs.i--; 10283a03b38SAndrey A. Chernov for (n = 0; n < 256; n++) { 103860c4e58SAndrey A. Chernov rs.i = (rs.i + 1); 104860c4e58SAndrey A. Chernov si = rs.s[rs.i]; 105860c4e58SAndrey A. Chernov rs.j = (rs.j + si + dat[n % datlen]); 106860c4e58SAndrey A. Chernov rs.s[rs.i] = rs.s[rs.j]; 107860c4e58SAndrey A. Chernov rs.s[rs.j] = si; 10883a03b38SAndrey A. Chernov } 109860c4e58SAndrey A. Chernov rs.j = rs.i; 11083a03b38SAndrey A. Chernov } 11183a03b38SAndrey A. Chernov 11283a03b38SAndrey A. Chernov static void 113860c4e58SAndrey A. Chernov arc4_stir(void) 11483a03b38SAndrey A. Chernov { 115c0b48470SDavid Schultz int done, fd, i; 11683a03b38SAndrey A. Chernov struct { 11783a03b38SAndrey A. Chernov struct timeval tv; 11883a03b38SAndrey A. Chernov pid_t pid; 119c0b48470SDavid Schultz u_char rnd[KEYSIZE]; 120913e28a4SAndrey A. Chernov } rdat; 12183a03b38SAndrey A. Chernov 122*7a0789b4SDavid Schultz if (!rs_initialized) { 123*7a0789b4SDavid Schultz arc4_init(); 124*7a0789b4SDavid Schultz rs_initialized = 1; 125*7a0789b4SDavid Schultz } 1266a05bf3aSAndrey A. Chernov fd = _open(RANDOMDEV, O_RDONLY, 0); 12789538e75SAndrey A. Chernov done = 0; 1286a05bf3aSAndrey A. Chernov if (fd >= 0) { 12989538e75SAndrey A. Chernov if (_read(fd, &rdat, KEYSIZE) == KEYSIZE) 13089538e75SAndrey A. Chernov done = 1; 13189538e75SAndrey A. Chernov (void)_close(fd); 132a08f5d95SAndrey A. Chernov } 13389538e75SAndrey A. Chernov if (!done) { 13489538e75SAndrey A. Chernov (void)gettimeofday(&rdat.tv, NULL); 13589538e75SAndrey A. Chernov rdat.pid = getpid(); 13689538e75SAndrey A. Chernov /* We'll just take whatever was on the stack too... */ 13789538e75SAndrey A. Chernov } 13883a03b38SAndrey A. Chernov 13989538e75SAndrey A. Chernov arc4_addrandom((u_char *)&rdat, KEYSIZE); 14060ce8b0eSDavid Schultz 14160ce8b0eSDavid Schultz /* 142c0b48470SDavid Schultz * Discard early keystream, as per recommendations in: 143c0b48470SDavid Schultz * "(Not So) Random Shuffles of RC4" by Ilya Mironov. 14460ce8b0eSDavid Schultz */ 145c0b48470SDavid Schultz for (i = 0; i < 1024; i++) 146860c4e58SAndrey A. Chernov (void)arc4_getbyte(); 1470761bd1fSAndrey A. Chernov arc4_count = 1600000; 14883a03b38SAndrey A. Chernov } 14983a03b38SAndrey A. Chernov 150*7a0789b4SDavid Schultz static void 151*7a0789b4SDavid Schultz arc4_stir_if_needed(void) 152*7a0789b4SDavid Schultz { 153*7a0789b4SDavid Schultz pid_t pid = getpid(); 154*7a0789b4SDavid Schultz 155*7a0789b4SDavid Schultz if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid) 156*7a0789b4SDavid Schultz { 157*7a0789b4SDavid Schultz arc4_stir_pid = pid; 158*7a0789b4SDavid Schultz arc4_stir(); 159*7a0789b4SDavid Schultz } 160*7a0789b4SDavid Schultz } 161*7a0789b4SDavid Schultz 16283a03b38SAndrey A. Chernov static inline u_int8_t 163860c4e58SAndrey A. Chernov arc4_getbyte(void) 16483a03b38SAndrey A. Chernov { 16583a03b38SAndrey A. Chernov u_int8_t si, sj; 16683a03b38SAndrey A. Chernov 167860c4e58SAndrey A. Chernov rs.i = (rs.i + 1); 168860c4e58SAndrey A. Chernov si = rs.s[rs.i]; 169860c4e58SAndrey A. Chernov rs.j = (rs.j + si); 170860c4e58SAndrey A. Chernov sj = rs.s[rs.j]; 171860c4e58SAndrey A. Chernov rs.s[rs.i] = sj; 172860c4e58SAndrey A. Chernov rs.s[rs.j] = si; 173860c4e58SAndrey A. Chernov return (rs.s[(si + sj) & 0xff]); 17483a03b38SAndrey A. Chernov } 17583a03b38SAndrey A. Chernov 17683a03b38SAndrey A. Chernov static inline u_int32_t 177860c4e58SAndrey A. Chernov arc4_getword(void) 17883a03b38SAndrey A. Chernov { 17983a03b38SAndrey A. Chernov u_int32_t val; 180860c4e58SAndrey A. Chernov val = arc4_getbyte() << 24; 181860c4e58SAndrey A. Chernov val |= arc4_getbyte() << 16; 182860c4e58SAndrey A. Chernov val |= arc4_getbyte() << 8; 183860c4e58SAndrey A. Chernov val |= arc4_getbyte(); 184c0b48470SDavid Schultz return val; 18583a03b38SAndrey A. Chernov } 18683a03b38SAndrey A. Chernov 1875295209eSBrian Feldman void 188cb4e06ebSXin LI arc4random_stir(void) 1895295209eSBrian Feldman { 190c0b48470SDavid Schultz _ARC4_LOCK(); 191860c4e58SAndrey A. Chernov arc4_stir(); 192c0b48470SDavid Schultz _ARC4_UNLOCK(); 19383a03b38SAndrey A. Chernov } 19483a03b38SAndrey A. Chernov 19583a03b38SAndrey A. Chernov void 196cb4e06ebSXin LI arc4random_addrandom(u_char *dat, int datlen) 19783a03b38SAndrey A. Chernov { 198c0b48470SDavid Schultz _ARC4_LOCK(); 199*7a0789b4SDavid Schultz if (!rs_initialized) 200*7a0789b4SDavid Schultz arc4_stir(); 201860c4e58SAndrey A. Chernov arc4_addrandom(dat, datlen); 202c0b48470SDavid Schultz _ARC4_UNLOCK(); 20383a03b38SAndrey A. Chernov } 20483a03b38SAndrey A. Chernov 20583a03b38SAndrey A. Chernov u_int32_t 206cb4e06ebSXin LI arc4random(void) 20783a03b38SAndrey A. Chernov { 208c0b48470SDavid Schultz u_int32_t val; 209c0b48470SDavid Schultz _ARC4_LOCK(); 210b6634bf8SAndrey A. Chernov arc4_count -= 4; 211*7a0789b4SDavid Schultz arc4_stir_if_needed(); 212*7a0789b4SDavid Schultz val = arc4_getword(); 213c0b48470SDavid Schultz _ARC4_UNLOCK(); 214c0b48470SDavid Schultz return val; 21583a03b38SAndrey A. Chernov } 21683a03b38SAndrey A. Chernov 217bc6847e2SAndrey A. Chernov void 218bc6847e2SAndrey A. Chernov arc4random_buf(void *_buf, size_t n) 219bc6847e2SAndrey A. Chernov { 220bc6847e2SAndrey A. Chernov u_char *buf = (u_char *)_buf; 221c0b48470SDavid Schultz _ARC4_LOCK(); 222*7a0789b4SDavid Schultz arc4_stir_if_needed(); 223bc6847e2SAndrey A. Chernov while (n--) { 224*7a0789b4SDavid Schultz if (--arc4_count <= 0) 225*7a0789b4SDavid Schultz arc4_stir(); 226860c4e58SAndrey A. Chernov buf[n] = arc4_getbyte(); 227bc6847e2SAndrey A. Chernov } 228c0b48470SDavid Schultz _ARC4_UNLOCK(); 229bc6847e2SAndrey A. Chernov } 230bc6847e2SAndrey A. Chernov 2316e4fe40aSAndrey A. Chernov /* 2326e4fe40aSAndrey A. Chernov * Calculate a uniformly distributed random number less than upper_bound 2336e4fe40aSAndrey A. Chernov * avoiding "modulo bias". 2346e4fe40aSAndrey A. Chernov * 2356e4fe40aSAndrey A. Chernov * Uniformity is achieved by generating new random numbers until the one 2366e4fe40aSAndrey A. Chernov * returned is outside the range [0, 2**32 % upper_bound). This 2376e4fe40aSAndrey A. Chernov * guarantees the selected random number will be inside 2386e4fe40aSAndrey A. Chernov * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound) 2396e4fe40aSAndrey A. Chernov * after reduction modulo upper_bound. 2406e4fe40aSAndrey A. Chernov */ 2416e4fe40aSAndrey A. Chernov u_int32_t 2426e4fe40aSAndrey A. Chernov arc4random_uniform(u_int32_t upper_bound) 2436e4fe40aSAndrey A. Chernov { 2446e4fe40aSAndrey A. Chernov u_int32_t r, min; 2456e4fe40aSAndrey A. Chernov 2466e4fe40aSAndrey A. Chernov if (upper_bound < 2) 247c0b48470SDavid Schultz return 0; 24861d35b63SAndrey A. Chernov 2496e4fe40aSAndrey A. Chernov #if (ULONG_MAX > 0xffffffffUL) 2506e4fe40aSAndrey A. Chernov min = 0x100000000UL % upper_bound; 2516e4fe40aSAndrey A. Chernov #else 2526e4fe40aSAndrey A. Chernov /* Calculate (2**32 % upper_bound) avoiding 64-bit math */ 2536e4fe40aSAndrey A. Chernov if (upper_bound > 0x80000000) 2546e4fe40aSAndrey A. Chernov min = 1 + ~upper_bound; /* 2**32 - upper_bound */ 2556e4fe40aSAndrey A. Chernov else { 2566e4fe40aSAndrey A. Chernov /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */ 2576e4fe40aSAndrey A. Chernov min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound; 2586e4fe40aSAndrey A. Chernov } 2596e4fe40aSAndrey A. Chernov #endif 2606e4fe40aSAndrey A. Chernov 2616e4fe40aSAndrey A. Chernov /* 2626e4fe40aSAndrey A. Chernov * This could theoretically loop forever but each retry has 2636e4fe40aSAndrey A. Chernov * p > 0.5 (worst case, usually far better) of selecting a 2646e4fe40aSAndrey A. Chernov * number inside the range we need, so it should rarely need 2656e4fe40aSAndrey A. Chernov * to re-roll. 2666e4fe40aSAndrey A. Chernov */ 2676e4fe40aSAndrey A. Chernov for (;;) { 2686e4fe40aSAndrey A. Chernov r = arc4random(); 2696e4fe40aSAndrey A. Chernov if (r >= min) 2706e4fe40aSAndrey A. Chernov break; 2716e4fe40aSAndrey A. Chernov } 2726e4fe40aSAndrey A. Chernov 273c0b48470SDavid Schultz return r % upper_bound; 2746e4fe40aSAndrey A. Chernov } 2756e4fe40aSAndrey A. Chernov 27683a03b38SAndrey A. Chernov #if 0 27783a03b38SAndrey A. Chernov /*-------- Test code for i386 --------*/ 27883a03b38SAndrey A. Chernov #include <stdio.h> 27983a03b38SAndrey A. Chernov #include <machine/pctr.h> 28083a03b38SAndrey A. Chernov int 28183a03b38SAndrey A. Chernov main(int argc, char **argv) 28283a03b38SAndrey A. Chernov { 28383a03b38SAndrey A. Chernov const int iter = 1000000; 28483a03b38SAndrey A. Chernov int i; 28583a03b38SAndrey A. Chernov pctrval v; 28683a03b38SAndrey A. Chernov 28783a03b38SAndrey A. Chernov v = rdtsc(); 28883a03b38SAndrey A. Chernov for (i = 0; i < iter; i++) 28983a03b38SAndrey A. Chernov arc4random(); 29083a03b38SAndrey A. Chernov v = rdtsc() - v; 29183a03b38SAndrey A. Chernov v /= iter; 29283a03b38SAndrey A. Chernov 29383a03b38SAndrey A. Chernov printf("%qd cycles\n", v); 29483a03b38SAndrey A. Chernov } 29583a03b38SAndrey A. Chernov #endif 296