1*c0b48470SDavid Schultz /* $OpenBSD: arc4random.c,v 1.22 2010/12/22 08:23:42 otto Exp $ */ 2*c0b48470SDavid 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" 36333fc21eSDavid E. O'Brien #include <sys/types.h> 37333fc21eSDavid E. O'Brien #include <sys/time.h> 3883a03b38SAndrey A. Chernov #include <stdlib.h> 3983a03b38SAndrey A. Chernov #include <fcntl.h> 4083a03b38SAndrey A. Chernov #include <unistd.h> 415295209eSBrian Feldman #include <pthread.h> 425295209eSBrian Feldman 435295209eSBrian Feldman #include "libc_private.h" 44d201fe46SDaniel Eischen #include "un-namespace.h" 4583a03b38SAndrey A. Chernov 46*c0b48470SDavid Schultz #ifdef __GNUC__ 47*c0b48470SDavid Schultz #define inline __inline 48*c0b48470SDavid Schultz #else /* !__GNUC__ */ 49*c0b48470SDavid Schultz #define inline 50*c0b48470SDavid Schultz #endif /* !__GNUC__ */ 51*c0b48470SDavid Schultz 5283a03b38SAndrey A. Chernov struct arc4_stream { 5383a03b38SAndrey A. Chernov u_int8_t i; 5483a03b38SAndrey A. Chernov u_int8_t j; 5583a03b38SAndrey A. Chernov u_int8_t s[256]; 5683a03b38SAndrey A. Chernov }; 5783a03b38SAndrey A. Chernov 585295209eSBrian Feldman static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; 595295209eSBrian Feldman 604220467eSAndrey A. Chernov #define RANDOMDEV "/dev/random" 6189538e75SAndrey A. Chernov #define KEYSIZE 128 62*c0b48470SDavid Schultz #define _ARC4_LOCK() \ 635295209eSBrian Feldman do { \ 645295209eSBrian Feldman if (__isthreaded) \ 655295209eSBrian Feldman _pthread_mutex_lock(&arc4random_mtx); \ 665295209eSBrian Feldman } while (0) 675295209eSBrian Feldman 68*c0b48470SDavid Schultz #define _ARC4_UNLOCK() \ 695295209eSBrian Feldman do { \ 705295209eSBrian Feldman if (__isthreaded) \ 715295209eSBrian Feldman _pthread_mutex_unlock(&arc4random_mtx); \ 725295209eSBrian Feldman } while (0) 735295209eSBrian Feldman 7483a03b38SAndrey A. Chernov static struct arc4_stream rs; 755295209eSBrian Feldman static int rs_initialized; 765295209eSBrian Feldman static int rs_stired; 77f68412f9SAndrey A. Chernov static int arc4_count; 7883a03b38SAndrey A. Chernov 79860c4e58SAndrey A. Chernov static inline u_int8_t arc4_getbyte(void); 80860c4e58SAndrey A. Chernov static void arc4_stir(void); 8160ce8b0eSDavid Schultz 8283a03b38SAndrey A. Chernov static inline void 83860c4e58SAndrey A. Chernov arc4_init(void) 8483a03b38SAndrey A. Chernov { 8583a03b38SAndrey A. Chernov int n; 8683a03b38SAndrey A. Chernov 8783a03b38SAndrey A. Chernov for (n = 0; n < 256; n++) 88860c4e58SAndrey A. Chernov rs.s[n] = n; 89860c4e58SAndrey A. Chernov rs.i = 0; 90860c4e58SAndrey A. Chernov rs.j = 0; 9183a03b38SAndrey A. Chernov } 9283a03b38SAndrey A. Chernov 9383a03b38SAndrey A. Chernov static inline void 94860c4e58SAndrey A. Chernov arc4_addrandom(u_char *dat, int datlen) 9583a03b38SAndrey A. Chernov { 9683a03b38SAndrey A. Chernov int n; 9783a03b38SAndrey A. Chernov u_int8_t si; 9883a03b38SAndrey A. Chernov 99860c4e58SAndrey A. Chernov rs.i--; 10083a03b38SAndrey A. Chernov for (n = 0; n < 256; n++) { 101860c4e58SAndrey A. Chernov rs.i = (rs.i + 1); 102860c4e58SAndrey A. Chernov si = rs.s[rs.i]; 103860c4e58SAndrey A. Chernov rs.j = (rs.j + si + dat[n % datlen]); 104860c4e58SAndrey A. Chernov rs.s[rs.i] = rs.s[rs.j]; 105860c4e58SAndrey A. Chernov rs.s[rs.j] = si; 10683a03b38SAndrey A. Chernov } 107860c4e58SAndrey A. Chernov rs.j = rs.i; 10883a03b38SAndrey A. Chernov } 10983a03b38SAndrey A. Chernov 11083a03b38SAndrey A. Chernov static void 111860c4e58SAndrey A. Chernov arc4_stir(void) 11283a03b38SAndrey A. Chernov { 113*c0b48470SDavid Schultz int done, fd, i; 11483a03b38SAndrey A. Chernov struct { 11583a03b38SAndrey A. Chernov struct timeval tv; 11683a03b38SAndrey A. Chernov pid_t pid; 117*c0b48470SDavid Schultz u_char rnd[KEYSIZE]; 118913e28a4SAndrey A. Chernov } rdat; 11983a03b38SAndrey A. Chernov 1206a05bf3aSAndrey A. Chernov fd = _open(RANDOMDEV, O_RDONLY, 0); 12189538e75SAndrey A. Chernov done = 0; 1226a05bf3aSAndrey A. Chernov if (fd >= 0) { 12389538e75SAndrey A. Chernov if (_read(fd, &rdat, KEYSIZE) == KEYSIZE) 12489538e75SAndrey A. Chernov done = 1; 12589538e75SAndrey A. Chernov (void)_close(fd); 126a08f5d95SAndrey A. Chernov } 12789538e75SAndrey A. Chernov if (!done) { 12889538e75SAndrey A. Chernov (void)gettimeofday(&rdat.tv, NULL); 12989538e75SAndrey A. Chernov rdat.pid = getpid(); 13089538e75SAndrey A. Chernov /* We'll just take whatever was on the stack too... */ 13189538e75SAndrey A. Chernov } 13283a03b38SAndrey A. Chernov 13389538e75SAndrey A. Chernov arc4_addrandom((u_char *)&rdat, KEYSIZE); 13460ce8b0eSDavid Schultz 13560ce8b0eSDavid Schultz /* 136*c0b48470SDavid Schultz * Discard early keystream, as per recommendations in: 137*c0b48470SDavid Schultz * "(Not So) Random Shuffles of RC4" by Ilya Mironov. 13860ce8b0eSDavid Schultz */ 139*c0b48470SDavid Schultz for (i = 0; i < 1024; i++) 140860c4e58SAndrey A. Chernov (void)arc4_getbyte(); 1410761bd1fSAndrey A. Chernov arc4_count = 1600000; 14283a03b38SAndrey A. Chernov } 14383a03b38SAndrey A. Chernov 14483a03b38SAndrey A. Chernov static inline u_int8_t 145860c4e58SAndrey A. Chernov arc4_getbyte(void) 14683a03b38SAndrey A. Chernov { 14783a03b38SAndrey A. Chernov u_int8_t si, sj; 14883a03b38SAndrey A. Chernov 149860c4e58SAndrey A. Chernov rs.i = (rs.i + 1); 150860c4e58SAndrey A. Chernov si = rs.s[rs.i]; 151860c4e58SAndrey A. Chernov rs.j = (rs.j + si); 152860c4e58SAndrey A. Chernov sj = rs.s[rs.j]; 153860c4e58SAndrey A. Chernov rs.s[rs.i] = sj; 154860c4e58SAndrey A. Chernov rs.s[rs.j] = si; 155860c4e58SAndrey A. Chernov return (rs.s[(si + sj) & 0xff]); 15683a03b38SAndrey A. Chernov } 15783a03b38SAndrey A. Chernov 15883a03b38SAndrey A. Chernov static inline u_int32_t 159860c4e58SAndrey A. Chernov arc4_getword(void) 16083a03b38SAndrey A. Chernov { 16183a03b38SAndrey A. Chernov u_int32_t val; 162860c4e58SAndrey A. Chernov val = arc4_getbyte() << 24; 163860c4e58SAndrey A. Chernov val |= arc4_getbyte() << 16; 164860c4e58SAndrey A. Chernov val |= arc4_getbyte() << 8; 165860c4e58SAndrey A. Chernov val |= arc4_getbyte(); 166*c0b48470SDavid Schultz return val; 16783a03b38SAndrey A. Chernov } 16883a03b38SAndrey A. Chernov 1695295209eSBrian Feldman static void 1705295209eSBrian Feldman arc4_check_init(void) 17183a03b38SAndrey A. Chernov { 17283a03b38SAndrey A. Chernov if (!rs_initialized) { 173860c4e58SAndrey A. Chernov arc4_init(); 1746a05bf3aSAndrey A. Chernov rs_initialized = 1; 17583a03b38SAndrey A. Chernov } 1765295209eSBrian Feldman } 1775295209eSBrian Feldman 178bc6847e2SAndrey A. Chernov static inline void 1795295209eSBrian Feldman arc4_check_stir(void) 1805295209eSBrian Feldman { 181b6634bf8SAndrey A. Chernov if (!rs_stired || arc4_count <= 0) { 182860c4e58SAndrey A. Chernov arc4_stir(); 1835295209eSBrian Feldman rs_stired = 1; 1845295209eSBrian Feldman } 1855295209eSBrian Feldman } 1865295209eSBrian Feldman 1875295209eSBrian Feldman void 188cb4e06ebSXin LI arc4random_stir(void) 1895295209eSBrian Feldman { 190*c0b48470SDavid Schultz _ARC4_LOCK(); 1915295209eSBrian Feldman arc4_check_init(); 192860c4e58SAndrey A. Chernov arc4_stir(); 1934220467eSAndrey A. Chernov rs_stired = 1; 194*c0b48470SDavid Schultz _ARC4_UNLOCK(); 19583a03b38SAndrey A. Chernov } 19683a03b38SAndrey A. Chernov 19783a03b38SAndrey A. Chernov void 198cb4e06ebSXin LI arc4random_addrandom(u_char *dat, int datlen) 19983a03b38SAndrey A. Chernov { 200*c0b48470SDavid Schultz _ARC4_LOCK(); 2015295209eSBrian Feldman arc4_check_init(); 2025295209eSBrian Feldman arc4_check_stir(); 203860c4e58SAndrey A. Chernov arc4_addrandom(dat, datlen); 204*c0b48470SDavid Schultz _ARC4_UNLOCK(); 20583a03b38SAndrey A. Chernov } 20683a03b38SAndrey A. Chernov 20783a03b38SAndrey A. Chernov u_int32_t 208cb4e06ebSXin LI arc4random(void) 20983a03b38SAndrey A. Chernov { 210*c0b48470SDavid Schultz u_int32_t val; 211*c0b48470SDavid Schultz _ARC4_LOCK(); 2125295209eSBrian Feldman arc4_check_init(); 2135295209eSBrian Feldman arc4_check_stir(); 214*c0b48470SDavid Schultz val = arc4_getword(); 215b6634bf8SAndrey A. Chernov arc4_count -= 4; 216*c0b48470SDavid Schultz _ARC4_UNLOCK(); 217*c0b48470SDavid Schultz return val; 21883a03b38SAndrey A. Chernov } 21983a03b38SAndrey A. Chernov 220bc6847e2SAndrey A. Chernov void 221bc6847e2SAndrey A. Chernov arc4random_buf(void *_buf, size_t n) 222bc6847e2SAndrey A. Chernov { 223bc6847e2SAndrey A. Chernov u_char *buf = (u_char *)_buf; 224*c0b48470SDavid Schultz _ARC4_LOCK(); 225bc6847e2SAndrey A. Chernov arc4_check_init(); 226bc6847e2SAndrey A. Chernov while (n--) { 227bc6847e2SAndrey A. Chernov arc4_check_stir(); 228860c4e58SAndrey A. Chernov buf[n] = arc4_getbyte(); 229bc6847e2SAndrey A. Chernov arc4_count--; 230bc6847e2SAndrey A. Chernov } 231*c0b48470SDavid Schultz _ARC4_UNLOCK(); 232bc6847e2SAndrey A. Chernov } 233bc6847e2SAndrey A. Chernov 2346e4fe40aSAndrey A. Chernov /* 2356e4fe40aSAndrey A. Chernov * Calculate a uniformly distributed random number less than upper_bound 2366e4fe40aSAndrey A. Chernov * avoiding "modulo bias". 2376e4fe40aSAndrey A. Chernov * 2386e4fe40aSAndrey A. Chernov * Uniformity is achieved by generating new random numbers until the one 2396e4fe40aSAndrey A. Chernov * returned is outside the range [0, 2**32 % upper_bound). This 2406e4fe40aSAndrey A. Chernov * guarantees the selected random number will be inside 2416e4fe40aSAndrey A. Chernov * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound) 2426e4fe40aSAndrey A. Chernov * after reduction modulo upper_bound. 2436e4fe40aSAndrey A. Chernov */ 2446e4fe40aSAndrey A. Chernov u_int32_t 2456e4fe40aSAndrey A. Chernov arc4random_uniform(u_int32_t upper_bound) 2466e4fe40aSAndrey A. Chernov { 2476e4fe40aSAndrey A. Chernov u_int32_t r, min; 2486e4fe40aSAndrey A. Chernov 2496e4fe40aSAndrey A. Chernov if (upper_bound < 2) 250*c0b48470SDavid Schultz return 0; 25161d35b63SAndrey A. Chernov 2526e4fe40aSAndrey A. Chernov #if (ULONG_MAX > 0xffffffffUL) 2536e4fe40aSAndrey A. Chernov min = 0x100000000UL % upper_bound; 2546e4fe40aSAndrey A. Chernov #else 2556e4fe40aSAndrey A. Chernov /* Calculate (2**32 % upper_bound) avoiding 64-bit math */ 2566e4fe40aSAndrey A. Chernov if (upper_bound > 0x80000000) 2576e4fe40aSAndrey A. Chernov min = 1 + ~upper_bound; /* 2**32 - upper_bound */ 2586e4fe40aSAndrey A. Chernov else { 2596e4fe40aSAndrey A. Chernov /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */ 2606e4fe40aSAndrey A. Chernov min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound; 2616e4fe40aSAndrey A. Chernov } 2626e4fe40aSAndrey A. Chernov #endif 2636e4fe40aSAndrey A. Chernov 2646e4fe40aSAndrey A. Chernov /* 2656e4fe40aSAndrey A. Chernov * This could theoretically loop forever but each retry has 2666e4fe40aSAndrey A. Chernov * p > 0.5 (worst case, usually far better) of selecting a 2676e4fe40aSAndrey A. Chernov * number inside the range we need, so it should rarely need 2686e4fe40aSAndrey A. Chernov * to re-roll. 2696e4fe40aSAndrey A. Chernov */ 2706e4fe40aSAndrey A. Chernov for (;;) { 2716e4fe40aSAndrey A. Chernov r = arc4random(); 2726e4fe40aSAndrey A. Chernov if (r >= min) 2736e4fe40aSAndrey A. Chernov break; 2746e4fe40aSAndrey A. Chernov } 2756e4fe40aSAndrey A. Chernov 276*c0b48470SDavid Schultz return r % upper_bound; 2776e4fe40aSAndrey A. Chernov } 2786e4fe40aSAndrey A. Chernov 27983a03b38SAndrey A. Chernov #if 0 28083a03b38SAndrey A. Chernov /*-------- Test code for i386 --------*/ 28183a03b38SAndrey A. Chernov #include <stdio.h> 28283a03b38SAndrey A. Chernov #include <machine/pctr.h> 28383a03b38SAndrey A. Chernov int 28483a03b38SAndrey A. Chernov main(int argc, char **argv) 28583a03b38SAndrey A. Chernov { 28683a03b38SAndrey A. Chernov const int iter = 1000000; 28783a03b38SAndrey A. Chernov int i; 28883a03b38SAndrey A. Chernov pctrval v; 28983a03b38SAndrey A. Chernov 29083a03b38SAndrey A. Chernov v = rdtsc(); 29183a03b38SAndrey A. Chernov for (i = 0; i < iter; i++) 29283a03b38SAndrey A. Chernov arc4random(); 29383a03b38SAndrey A. Chernov v = rdtsc() - v; 29483a03b38SAndrey A. Chernov v /= iter; 29583a03b38SAndrey A. Chernov 29683a03b38SAndrey A. Chernov printf("%qd cycles\n", v); 29783a03b38SAndrey A. Chernov } 29883a03b38SAndrey A. Chernov #endif 299