1dad64c97SPedro F. Giffuni /* $OpenBSD: arc4random.c,v 1.24 2013/06/11 16:59:50 deraadt 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> 377a0789b4SDavid Schultz #include <limits.h> 387a0789b4SDavid Schultz #include <stdlib.h> 3983a03b38SAndrey A. Chernov #include <unistd.h> 407a0789b4SDavid Schultz #include <sys/param.h> 4172de35d0SPawel Jakub Dawidek #include <sys/sysctl.h> 427a0789b4SDavid 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; 777a0789b4SDavid Schultz static struct arc4_stream rs; 787a0789b4SDavid Schultz static pid_t arc4_stir_pid; 79f68412f9SAndrey A. Chernov static int arc4_count; 8083a03b38SAndrey A. Chernov 8172de35d0SPawel Jakub Dawidek extern int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, 8272de35d0SPawel Jakub Dawidek void *newp, size_t newlen); 8372de35d0SPawel Jakub Dawidek 84860c4e58SAndrey A. Chernov static inline u_int8_t arc4_getbyte(void); 85860c4e58SAndrey A. Chernov static void arc4_stir(void); 8660ce8b0eSDavid Schultz 8783a03b38SAndrey A. Chernov static inline void 88860c4e58SAndrey A. Chernov arc4_init(void) 8983a03b38SAndrey A. Chernov { 9083a03b38SAndrey A. Chernov int n; 9183a03b38SAndrey A. Chernov 9283a03b38SAndrey A. Chernov for (n = 0; n < 256; n++) 93860c4e58SAndrey A. Chernov rs.s[n] = n; 94860c4e58SAndrey A. Chernov rs.i = 0; 95860c4e58SAndrey A. Chernov rs.j = 0; 9683a03b38SAndrey A. Chernov } 9783a03b38SAndrey A. Chernov 9883a03b38SAndrey A. Chernov static inline void 99860c4e58SAndrey A. Chernov arc4_addrandom(u_char *dat, int datlen) 10083a03b38SAndrey A. Chernov { 10183a03b38SAndrey A. Chernov int n; 10283a03b38SAndrey A. Chernov u_int8_t si; 10383a03b38SAndrey A. Chernov 104860c4e58SAndrey A. Chernov rs.i--; 10583a03b38SAndrey A. Chernov for (n = 0; n < 256; n++) { 106860c4e58SAndrey A. Chernov rs.i = (rs.i + 1); 107860c4e58SAndrey A. Chernov si = rs.s[rs.i]; 108860c4e58SAndrey A. Chernov rs.j = (rs.j + si + dat[n % datlen]); 109860c4e58SAndrey A. Chernov rs.s[rs.i] = rs.s[rs.j]; 110860c4e58SAndrey A. Chernov rs.s[rs.j] = si; 11183a03b38SAndrey A. Chernov } 112860c4e58SAndrey A. Chernov rs.j = rs.i; 11383a03b38SAndrey A. Chernov } 11483a03b38SAndrey A. Chernov 11572de35d0SPawel Jakub Dawidek static size_t 11672de35d0SPawel Jakub Dawidek arc4_sysctl(u_char *buf, size_t size) 11772de35d0SPawel Jakub Dawidek { 11872de35d0SPawel Jakub Dawidek int mib[2]; 11972de35d0SPawel Jakub Dawidek size_t len, done; 12072de35d0SPawel Jakub Dawidek 12172de35d0SPawel Jakub Dawidek mib[0] = CTL_KERN; 12272de35d0SPawel Jakub Dawidek mib[1] = KERN_ARND; 12372de35d0SPawel Jakub Dawidek done = 0; 12472de35d0SPawel Jakub Dawidek 12572de35d0SPawel Jakub Dawidek do { 12672de35d0SPawel Jakub Dawidek len = size; 12772de35d0SPawel Jakub Dawidek if (__sysctl(mib, 2, buf, &len, NULL, 0) == -1) 12872de35d0SPawel Jakub Dawidek return (done); 12972de35d0SPawel Jakub Dawidek done += len; 13072de35d0SPawel Jakub Dawidek buf += len; 13172de35d0SPawel Jakub Dawidek size -= len; 13272de35d0SPawel Jakub Dawidek } while (size > 0); 13372de35d0SPawel Jakub Dawidek 13472de35d0SPawel Jakub Dawidek return (done); 13572de35d0SPawel Jakub Dawidek } 13672de35d0SPawel Jakub Dawidek 13783a03b38SAndrey A. Chernov static void 138860c4e58SAndrey A. Chernov arc4_stir(void) 13983a03b38SAndrey A. Chernov { 1405c1ea1fcSEd Maste u_char rdat[KEYSIZE]; 1415c1ea1fcSEd Maste int i; 14283a03b38SAndrey A. Chernov 1437a0789b4SDavid Schultz if (!rs_initialized) { 1447a0789b4SDavid Schultz arc4_init(); 1457a0789b4SDavid Schultz rs_initialized = 1; 1467a0789b4SDavid Schultz } 147*49a6e1baSEd Maste if (arc4_sysctl(rdat, KEYSIZE) != KEYSIZE) { 148*49a6e1baSEd Maste /* 149*49a6e1baSEd Maste * The sysctl cannot fail. If it does fail on some FreeBSD 150*49a6e1baSEd Maste * derivative or after some future change, just abort so that 151*49a6e1baSEd Maste * the problem will be found and fixed. abort is not normally 152*49a6e1baSEd Maste * suitable for a library but makes sense here. 153*49a6e1baSEd Maste */ 154*49a6e1baSEd Maste abort(); 155*49a6e1baSEd Maste } 15683a03b38SAndrey A. Chernov 1575c1ea1fcSEd Maste arc4_addrandom(rdat, KEYSIZE); 15860ce8b0eSDavid Schultz 15960ce8b0eSDavid Schultz /* 160c0b48470SDavid Schultz * Discard early keystream, as per recommendations in: 161c0b48470SDavid Schultz * "(Not So) Random Shuffles of RC4" by Ilya Mironov. 16260ce8b0eSDavid Schultz */ 163c0b48470SDavid Schultz for (i = 0; i < 1024; i++) 164860c4e58SAndrey A. Chernov (void)arc4_getbyte(); 1650761bd1fSAndrey A. Chernov arc4_count = 1600000; 16683a03b38SAndrey A. Chernov } 16783a03b38SAndrey A. Chernov 1687a0789b4SDavid Schultz static void 1697a0789b4SDavid Schultz arc4_stir_if_needed(void) 1707a0789b4SDavid Schultz { 1717a0789b4SDavid Schultz pid_t pid = getpid(); 1727a0789b4SDavid Schultz 173dad64c97SPedro F. Giffuni if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid) { 1747a0789b4SDavid Schultz arc4_stir_pid = pid; 1757a0789b4SDavid Schultz arc4_stir(); 1767a0789b4SDavid Schultz } 1777a0789b4SDavid Schultz } 1787a0789b4SDavid Schultz 17983a03b38SAndrey A. Chernov static inline u_int8_t 180860c4e58SAndrey A. Chernov arc4_getbyte(void) 18183a03b38SAndrey A. Chernov { 18283a03b38SAndrey A. Chernov u_int8_t si, sj; 18383a03b38SAndrey A. Chernov 184860c4e58SAndrey A. Chernov rs.i = (rs.i + 1); 185860c4e58SAndrey A. Chernov si = rs.s[rs.i]; 186860c4e58SAndrey A. Chernov rs.j = (rs.j + si); 187860c4e58SAndrey A. Chernov sj = rs.s[rs.j]; 188860c4e58SAndrey A. Chernov rs.s[rs.i] = sj; 189860c4e58SAndrey A. Chernov rs.s[rs.j] = si; 190860c4e58SAndrey A. Chernov return (rs.s[(si + sj) & 0xff]); 19183a03b38SAndrey A. Chernov } 19283a03b38SAndrey A. Chernov 19383a03b38SAndrey A. Chernov static inline u_int32_t 194860c4e58SAndrey A. Chernov arc4_getword(void) 19583a03b38SAndrey A. Chernov { 19683a03b38SAndrey A. Chernov u_int32_t val; 197860c4e58SAndrey A. Chernov val = arc4_getbyte() << 24; 198860c4e58SAndrey A. Chernov val |= arc4_getbyte() << 16; 199860c4e58SAndrey A. Chernov val |= arc4_getbyte() << 8; 200860c4e58SAndrey A. Chernov val |= arc4_getbyte(); 201c0b48470SDavid Schultz return val; 20283a03b38SAndrey A. Chernov } 20383a03b38SAndrey A. Chernov 2045295209eSBrian Feldman void 205cb4e06ebSXin LI arc4random_stir(void) 2065295209eSBrian Feldman { 207c0b48470SDavid Schultz _ARC4_LOCK(); 208860c4e58SAndrey A. Chernov arc4_stir(); 209c0b48470SDavid Schultz _ARC4_UNLOCK(); 21083a03b38SAndrey A. Chernov } 21183a03b38SAndrey A. Chernov 21283a03b38SAndrey A. Chernov void 213cb4e06ebSXin LI arc4random_addrandom(u_char *dat, int datlen) 21483a03b38SAndrey A. Chernov { 215c0b48470SDavid Schultz _ARC4_LOCK(); 2167a0789b4SDavid Schultz if (!rs_initialized) 2177a0789b4SDavid Schultz arc4_stir(); 218860c4e58SAndrey A. Chernov arc4_addrandom(dat, datlen); 219c0b48470SDavid Schultz _ARC4_UNLOCK(); 22083a03b38SAndrey A. Chernov } 22183a03b38SAndrey A. Chernov 22283a03b38SAndrey A. Chernov u_int32_t 223cb4e06ebSXin LI arc4random(void) 22483a03b38SAndrey A. Chernov { 225c0b48470SDavid Schultz u_int32_t val; 226c0b48470SDavid Schultz _ARC4_LOCK(); 227b6634bf8SAndrey A. Chernov arc4_count -= 4; 2287a0789b4SDavid Schultz arc4_stir_if_needed(); 2297a0789b4SDavid Schultz val = arc4_getword(); 230c0b48470SDavid Schultz _ARC4_UNLOCK(); 231c0b48470SDavid Schultz return val; 23283a03b38SAndrey A. Chernov } 23383a03b38SAndrey A. Chernov 234bc6847e2SAndrey A. Chernov void 235bc6847e2SAndrey A. Chernov arc4random_buf(void *_buf, size_t n) 236bc6847e2SAndrey A. Chernov { 237bc6847e2SAndrey A. Chernov u_char *buf = (u_char *)_buf; 238c0b48470SDavid Schultz _ARC4_LOCK(); 2397a0789b4SDavid Schultz arc4_stir_if_needed(); 240bc6847e2SAndrey A. Chernov while (n--) { 2417a0789b4SDavid Schultz if (--arc4_count <= 0) 2427a0789b4SDavid Schultz arc4_stir(); 243860c4e58SAndrey A. Chernov buf[n] = arc4_getbyte(); 244bc6847e2SAndrey A. Chernov } 245c0b48470SDavid Schultz _ARC4_UNLOCK(); 246bc6847e2SAndrey A. Chernov } 247bc6847e2SAndrey A. Chernov 2486e4fe40aSAndrey A. Chernov /* 2496e4fe40aSAndrey A. Chernov * Calculate a uniformly distributed random number less than upper_bound 2506e4fe40aSAndrey A. Chernov * avoiding "modulo bias". 2516e4fe40aSAndrey A. Chernov * 2526e4fe40aSAndrey A. Chernov * Uniformity is achieved by generating new random numbers until the one 2536e4fe40aSAndrey A. Chernov * returned is outside the range [0, 2**32 % upper_bound). This 2546e4fe40aSAndrey A. Chernov * guarantees the selected random number will be inside 2556e4fe40aSAndrey A. Chernov * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound) 2566e4fe40aSAndrey A. Chernov * after reduction modulo upper_bound. 2576e4fe40aSAndrey A. Chernov */ 2586e4fe40aSAndrey A. Chernov u_int32_t 2596e4fe40aSAndrey A. Chernov arc4random_uniform(u_int32_t upper_bound) 2606e4fe40aSAndrey A. Chernov { 2616e4fe40aSAndrey A. Chernov u_int32_t r, min; 2626e4fe40aSAndrey A. Chernov 2636e4fe40aSAndrey A. Chernov if (upper_bound < 2) 264c0b48470SDavid Schultz return 0; 26561d35b63SAndrey A. Chernov 266dad64c97SPedro F. Giffuni /* 2**32 % x == (2**32 - x) % x */ 267dad64c97SPedro F. Giffuni min = -upper_bound % upper_bound; 2686e4fe40aSAndrey A. Chernov /* 2696e4fe40aSAndrey A. Chernov * This could theoretically loop forever but each retry has 2706e4fe40aSAndrey A. Chernov * p > 0.5 (worst case, usually far better) of selecting a 2716e4fe40aSAndrey A. Chernov * number inside the range we need, so it should rarely need 2726e4fe40aSAndrey A. Chernov * to re-roll. 2736e4fe40aSAndrey A. Chernov */ 2746e4fe40aSAndrey A. Chernov for (;;) { 2756e4fe40aSAndrey A. Chernov r = arc4random(); 2766e4fe40aSAndrey A. Chernov if (r >= min) 2776e4fe40aSAndrey A. Chernov break; 2786e4fe40aSAndrey A. Chernov } 2796e4fe40aSAndrey A. Chernov 280c0b48470SDavid Schultz return r % upper_bound; 2816e4fe40aSAndrey A. Chernov } 2826e4fe40aSAndrey A. Chernov 28383a03b38SAndrey A. Chernov #if 0 28483a03b38SAndrey A. Chernov /*-------- Test code for i386 --------*/ 28583a03b38SAndrey A. Chernov #include <stdio.h> 28683a03b38SAndrey A. Chernov #include <machine/pctr.h> 28783a03b38SAndrey A. Chernov int 28883a03b38SAndrey A. Chernov main(int argc, char **argv) 28983a03b38SAndrey A. Chernov { 29083a03b38SAndrey A. Chernov const int iter = 1000000; 29183a03b38SAndrey A. Chernov int i; 29283a03b38SAndrey A. Chernov pctrval v; 29383a03b38SAndrey A. Chernov 29483a03b38SAndrey A. Chernov v = rdtsc(); 29583a03b38SAndrey A. Chernov for (i = 0; i < iter; i++) 29683a03b38SAndrey A. Chernov arc4random(); 29783a03b38SAndrey A. Chernov v = rdtsc() - v; 29883a03b38SAndrey A. Chernov v /= iter; 29983a03b38SAndrey A. Chernov 30083a03b38SAndrey A. Chernov printf("%qd cycles\n", v); 30183a03b38SAndrey A. Chernov } 30283a03b38SAndrey A. Chernov #endif 303