1ee3fd601SDan Moschuk /*- 2ee3fd601SDan Moschuk * THE BEER-WARE LICENSE 3ee3fd601SDan Moschuk * 4ee3fd601SDan Moschuk * <dan@FreeBSD.ORG> wrote this file. As long as you retain this notice you 5ee3fd601SDan Moschuk * can do whatever you want with this stuff. If we meet some day, and you 6ee3fd601SDan Moschuk * think this stuff is worth it, you can buy me a beer in return. 7ee3fd601SDan Moschuk * 8ee3fd601SDan Moschuk * Dan Moschuk 9ee3fd601SDan Moschuk */ 10ee3fd601SDan Moschuk 11ab0de15bSDavid E. O'Brien #include <sys/cdefs.h> 12ab0de15bSDavid E. O'Brien __FBSDID("$FreeBSD$"); 13ab0de15bSDavid E. O'Brien 14bf3191e9SMark Murray #include <sys/types.h> 152f823fa3SMike Silbersack #include <sys/param.h> 162f823fa3SMike Silbersack #include <sys/kernel.h> 17bf3191e9SMark Murray #include <sys/random.h> 18ee3fd601SDan Moschuk #include <sys/libkern.h> 192f823fa3SMike Silbersack #include <sys/lock.h> 202f823fa3SMike Silbersack #include <sys/mutex.h> 213a7810bcSMike Silbersack #include <sys/time.h> 22*dcf33028SFabien Thomas #include <sys/smp.h> 23*dcf33028SFabien Thomas #include <sys/malloc.h> 24d65b1670SDan Moschuk 252c38619bSPoul-Henning Kamp #define ARC4_RESEED_BYTES 65536 263a7810bcSMike Silbersack #define ARC4_RESEED_SECONDS 300 27d1b06863SMark Murray #define ARC4_KEYBYTES 256 28ee3fd601SDan Moschuk 292b50ce65SAndrey A. Chernov int arc4rand_iniseed_state = ARC4_ENTR_NONE; 302b50ce65SAndrey A. Chernov 31*dcf33028SFabien Thomas MALLOC_DEFINE(M_ARC4RANDOM, "arc4random", "arc4random structures"); 323a7810bcSMike Silbersack 33*dcf33028SFabien Thomas struct arc4_s { 34*dcf33028SFabien Thomas u_int8_t i, j; 35*dcf33028SFabien Thomas int numruns; 36*dcf33028SFabien Thomas u_int8_t sbox[256]; 37*dcf33028SFabien Thomas time_t t_reseed; 38*dcf33028SFabien Thomas 39*dcf33028SFabien Thomas struct mtx mtx; 40*dcf33028SFabien Thomas }; 41*dcf33028SFabien Thomas 42*dcf33028SFabien Thomas static struct arc4_s *arc4inst = NULL; 43*dcf33028SFabien Thomas 44*dcf33028SFabien Thomas #define ARC4_FOREACH(_arc4) \ 45*dcf33028SFabien Thomas for (_arc4 = &arc4inst[0]; _arc4 <= &arc4inst[mp_maxid]; _arc4++) 46*dcf33028SFabien Thomas 47*dcf33028SFabien Thomas static u_int8_t arc4_randbyte(struct arc4_s *arc4); 48ee3fd601SDan Moschuk 49ee3fd601SDan Moschuk static __inline void 50ee3fd601SDan Moschuk arc4_swap(u_int8_t *a, u_int8_t *b) 51ee3fd601SDan Moschuk { 52ee3fd601SDan Moschuk u_int8_t c; 53ee3fd601SDan Moschuk 54ee3fd601SDan Moschuk c = *a; 55ee3fd601SDan Moschuk *a = *b; 56ee3fd601SDan Moschuk *b = c; 57ee3fd601SDan Moschuk } 58ee3fd601SDan Moschuk 59ee3fd601SDan Moschuk /* 60d65b1670SDan Moschuk * Stir our S-box. 61d65b1670SDan Moschuk */ 62d65b1670SDan Moschuk static void 63*dcf33028SFabien Thomas arc4_randomstir(struct arc4_s* arc4) 64d65b1670SDan Moschuk { 65d1b06863SMark Murray u_int8_t key[ARC4_KEYBYTES]; 66d1b06863SMark Murray int n; 672c38619bSPoul-Henning Kamp struct timeval tv_now; 68d65b1670SDan Moschuk 6960f8e3afSBruce Evans /* 70d1b06863SMark Murray * XXX: FIX!! This isn't brilliant. Need more confidence. 71d1b06863SMark Murray * This returns zero entropy before random(4) is seeded. 724cb1e539SMark Murray */ 73d1b06863SMark Murray (void)read_random(key, ARC4_KEYBYTES); 742f823fa3SMike Silbersack getmicrouptime(&tv_now); 75*dcf33028SFabien Thomas mtx_lock(&arc4->mtx); 762c38619bSPoul-Henning Kamp for (n = 0; n < 256; n++) { 77*dcf33028SFabien Thomas arc4->j = (arc4->j + arc4->sbox[n] + key[n]) % 256; 78*dcf33028SFabien Thomas arc4_swap(&arc4->sbox[n], &arc4->sbox[arc4->j]); 79d65b1670SDan Moschuk } 80*dcf33028SFabien Thomas arc4->i = arc4->j = 0; 813a7810bcSMike Silbersack /* Reset for next reseed cycle. */ 82*dcf33028SFabien Thomas arc4->t_reseed = tv_now.tv_sec + ARC4_RESEED_SECONDS; 83*dcf33028SFabien Thomas arc4->numruns = 0; 842f823fa3SMike Silbersack /* 85fff6495eSAndrey A. Chernov * Throw away the first N words of output, as suggested in the 862f823fa3SMike Silbersack * paper "Weaknesses in the Key Scheduling Algorithm of RC4" 87fff6495eSAndrey A. Chernov * by Fluher, Mantin, and Shamir. (N = 256 in our case.) 88d1b06863SMark Murray * 89d1b06863SMark Murray * http://dl.acm.org/citation.cfm?id=646557.694759 902f823fa3SMike Silbersack */ 91fff6495eSAndrey A. Chernov for (n = 0; n < 256*4; n++) 92*dcf33028SFabien Thomas arc4_randbyte(arc4); 93*dcf33028SFabien Thomas 94*dcf33028SFabien Thomas mtx_unlock(&arc4->mtx); 95d65b1670SDan Moschuk } 96d65b1670SDan Moschuk 97d65b1670SDan Moschuk /* 98ee3fd601SDan Moschuk * Initialize our S-box to its beginning defaults. 99ee3fd601SDan Moschuk */ 100ee3fd601SDan Moschuk static void 101ee3fd601SDan Moschuk arc4_init(void) 102ee3fd601SDan Moschuk { 103*dcf33028SFabien Thomas struct arc4_s *arc4; 104ee3fd601SDan Moschuk int n; 105ee3fd601SDan Moschuk 106*dcf33028SFabien Thomas arc4inst = malloc((mp_maxid + 1) * sizeof(struct arc4_s), 107*dcf33028SFabien Thomas M_ARC4RANDOM, M_NOWAIT | M_ZERO); 108*dcf33028SFabien Thomas KASSERT(arc4inst != NULL, ("arc4_init: memory allocation error")); 109d65b1670SDan Moschuk 110*dcf33028SFabien Thomas ARC4_FOREACH(arc4) { 111*dcf33028SFabien Thomas mtx_init(&arc4->mtx, "arc4_mtx", NULL, MTX_DEF); 112*dcf33028SFabien Thomas 113*dcf33028SFabien Thomas arc4->i = arc4->j = 0; 114*dcf33028SFabien Thomas for (n = 0; n < 256; n++) 115*dcf33028SFabien Thomas arc4->sbox[n] = (u_int8_t) n; 116*dcf33028SFabien Thomas 117*dcf33028SFabien Thomas arc4->t_reseed = -1; 118*dcf33028SFabien Thomas arc4->numruns = 0; 119*dcf33028SFabien Thomas } 120*dcf33028SFabien Thomas } 121*dcf33028SFabien Thomas SYSINIT(arc4, SI_SUB_LOCK, SI_ORDER_ANY, arc4_init, NULL); 122*dcf33028SFabien Thomas 123*dcf33028SFabien Thomas 124*dcf33028SFabien Thomas static void 125*dcf33028SFabien Thomas arc4_uninit(void) 126*dcf33028SFabien Thomas { 127*dcf33028SFabien Thomas struct arc4_s *arc4; 128*dcf33028SFabien Thomas 129*dcf33028SFabien Thomas ARC4_FOREACH(arc4) { 130*dcf33028SFabien Thomas mtx_destroy(&arc4->mtx); 131ee3fd601SDan Moschuk } 132ee3fd601SDan Moschuk 133*dcf33028SFabien Thomas free(arc4inst, M_ARC4RANDOM); 134*dcf33028SFabien Thomas } 135*dcf33028SFabien Thomas 136*dcf33028SFabien Thomas SYSUNINIT(arc4, SI_SUB_LOCK, SI_ORDER_ANY, arc4_uninit, NULL); 137*dcf33028SFabien Thomas 1382f823fa3SMike Silbersack 139ee3fd601SDan Moschuk /* 140ee3fd601SDan Moschuk * Generate a random byte. 141ee3fd601SDan Moschuk */ 142ee3fd601SDan Moschuk static u_int8_t 143*dcf33028SFabien Thomas arc4_randbyte(struct arc4_s *arc4) 144ee3fd601SDan Moschuk { 145ee3fd601SDan Moschuk u_int8_t arc4_t; 146ee3fd601SDan Moschuk 147*dcf33028SFabien Thomas arc4->i = (arc4->i + 1) % 256; 148*dcf33028SFabien Thomas arc4->j = (arc4->j + arc4->sbox[arc4->i]) % 256; 149ee3fd601SDan Moschuk 150*dcf33028SFabien Thomas arc4_swap(&arc4->sbox[arc4->i], &arc4->sbox[arc4->j]); 151ee3fd601SDan Moschuk 152*dcf33028SFabien Thomas arc4_t = (arc4->sbox[arc4->i] + arc4->sbox[arc4->j]) % 256; 153*dcf33028SFabien Thomas return arc4->sbox[arc4_t]; 154ee3fd601SDan Moschuk } 155ee3fd601SDan Moschuk 1562f823fa3SMike Silbersack /* 1572f823fa3SMike Silbersack * MPSAFE 1582f823fa3SMike Silbersack */ 1592c38619bSPoul-Henning Kamp void 1602c38619bSPoul-Henning Kamp arc4rand(void *ptr, u_int len, int reseed) 161ee3fd601SDan Moschuk { 1622c38619bSPoul-Henning Kamp u_char *p; 1632c38619bSPoul-Henning Kamp struct timeval tv; 164*dcf33028SFabien Thomas struct arc4_s *arc4; 165ee3fd601SDan Moschuk 166*dcf33028SFabien Thomas if (reseed || atomic_cmpset_int(&arc4rand_iniseed_state, 167*dcf33028SFabien Thomas ARC4_ENTR_HAVE, ARC4_ENTR_SEED)) { 168*dcf33028SFabien Thomas ARC4_FOREACH(arc4) 169*dcf33028SFabien Thomas arc4_randomstir(arc4); 170*dcf33028SFabien Thomas } 171*dcf33028SFabien Thomas 172*dcf33028SFabien Thomas arc4 = &arc4inst[curcpu]; 1732c38619bSPoul-Henning Kamp getmicrouptime(&tv); 174*dcf33028SFabien Thomas if ((arc4->numruns > ARC4_RESEED_BYTES) || 175*dcf33028SFabien Thomas (tv.tv_sec > arc4->t_reseed)) 176*dcf33028SFabien Thomas arc4_randomstir(arc4); 1772c38619bSPoul-Henning Kamp 178*dcf33028SFabien Thomas mtx_lock(&arc4->mtx); 179*dcf33028SFabien Thomas arc4->numruns += len; 1802c38619bSPoul-Henning Kamp p = ptr; 1812c38619bSPoul-Henning Kamp while (len--) 182*dcf33028SFabien Thomas *p++ = arc4_randbyte(arc4); 183*dcf33028SFabien Thomas mtx_unlock(&arc4->mtx); 184d65b1670SDan Moschuk } 185ee3fd601SDan Moschuk 1862c38619bSPoul-Henning Kamp uint32_t 1872c38619bSPoul-Henning Kamp arc4random(void) 1882c38619bSPoul-Henning Kamp { 1892c38619bSPoul-Henning Kamp uint32_t ret; 190ee3fd601SDan Moschuk 1912c38619bSPoul-Henning Kamp arc4rand(&ret, sizeof ret, 0); 192ee3fd601SDan Moschuk return ret; 193ee3fd601SDan Moschuk } 194