153842Sdan/*- 253842Sdan * THE BEER-WARE LICENSE 353842Sdan * 453842Sdan * <dan@FreeBSD.ORG> wrote this file. As long as you retain this notice you 553842Sdan * can do whatever you want with this stuff. If we meet some day, and you 653842Sdan * think this stuff is worth it, you can buy me a beer in return. 753842Sdan * 853842Sdan * Dan Moschuk 953842Sdan */ 1053842Sdan 11116189Sobrien#include <sys/cdefs.h> 12116189Sobrien__FBSDID("$FreeBSD$"); 13116189Sobrien 1462072Smarkm#include <sys/types.h> 15118938Ssilby#include <sys/param.h> 16118938Ssilby#include <sys/kernel.h> 1762072Smarkm#include <sys/random.h> 1853842Sdan#include <sys/libkern.h> 19118938Ssilby#include <sys/lock.h> 20118938Ssilby#include <sys/mutex.h> 2182543Ssilby#include <sys/time.h> 2253842Sdan 23104900Sphk#define ARC4_RESEED_BYTES 65536 2482543Ssilby#define ARC4_RESEED_SECONDS 300 25104900Sphk#define ARC4_KEYBYTES (256 / 8) 2653864Sdan 27249631Sacheint arc4rand_iniseed_state = ARC4_ENTR_NONE; 28249631Sache 2953842Sdanstatic u_int8_t arc4_i, arc4_j; 3053864Sdanstatic int arc4_numruns = 0; 3153842Sdanstatic u_int8_t arc4_sbox[256]; 32104900Sphkstatic time_t arc4_t_reseed; 33118938Ssilbystatic struct mtx arc4_mtx; 3453842Sdan 3582543Ssilbystatic u_int8_t arc4_randbyte(void); 3682543Ssilby 3753842Sdanstatic __inline void 3853842Sdanarc4_swap(u_int8_t *a, u_int8_t *b) 3953842Sdan{ 4053842Sdan u_int8_t c; 4153842Sdan 4253842Sdan c = *a; 4353842Sdan *a = *b; 4453842Sdan *b = c; 4553842Sdan} 4653842Sdan 4753842Sdan/* 4853864Sdan * Stir our S-box. 4953864Sdan */ 5053864Sdanstatic void 5153864Sdanarc4_randomstir (void) 5253864Sdan{ 5353864Sdan u_int8_t key[256]; 5453864Sdan int r, n; 55104900Sphk struct timeval tv_now; 5653864Sdan 5782565Sbde /* 5882565Sbde * XXX read_random() returns unsafe numbers if the entropy 5982565Sbde * device is not loaded -- MarkM. 6069520Smarkm */ 6182543Ssilby r = read_random(key, ARC4_KEYBYTES); 62118938Ssilby getmicrouptime(&tv_now); 63118938Ssilby mtx_lock(&arc4_mtx); 6482565Sbde /* If r == 0 || -1, just use what was on the stack. */ 65104900Sphk if (r > 0) { 6653893Sdan for (n = r; n < sizeof(key); n++) 6753893Sdan key[n] = key[n % r]; 6853893Sdan } 6953864Sdan 70104900Sphk for (n = 0; n < 256; n++) { 7153864Sdan arc4_j = (arc4_j + arc4_sbox[n] + key[n]) % 256; 7253864Sdan arc4_swap(&arc4_sbox[n], &arc4_sbox[arc4_j]); 7353864Sdan } 74180825Sache arc4_i = arc4_j = 0; 7582543Ssilby 7682543Ssilby /* Reset for next reseed cycle. */ 77104900Sphk arc4_t_reseed = tv_now.tv_sec + ARC4_RESEED_SECONDS; 7882543Ssilby arc4_numruns = 0; 79118938Ssilby 80118938Ssilby /* 81180805Sache * Throw away the first N words of output, as suggested in the 82118938Ssilby * paper "Weaknesses in the Key Scheduling Algorithm of RC4" 83180805Sache * by Fluher, Mantin, and Shamir. (N = 256 in our case.) 84118938Ssilby */ 85180805Sache for (n = 0; n < 256*4; n++) 86180805Sache arc4_randbyte(); 87118938Ssilby mtx_unlock(&arc4_mtx); 8853864Sdan} 8953864Sdan 9053864Sdan/* 9153842Sdan * Initialize our S-box to its beginning defaults. 9253842Sdan */ 9353842Sdanstatic void 9453842Sdanarc4_init(void) 9553842Sdan{ 9653842Sdan int n; 9753842Sdan 98118938Ssilby mtx_init(&arc4_mtx, "arc4_mtx", NULL, MTX_DEF); 9953864Sdan arc4_i = arc4_j = 0; 10053842Sdan for (n = 0; n < 256; n++) 10153842Sdan arc4_sbox[n] = (u_int8_t) n; 10253842Sdan 103118938Ssilby arc4_t_reseed = 0; 10453842Sdan} 10553842Sdan 106118938SsilbySYSINIT(arc4_init, SI_SUB_LOCK, SI_ORDER_ANY, arc4_init, NULL); 107118938Ssilby 10853842Sdan/* 10953842Sdan * Generate a random byte. 11053842Sdan */ 11153842Sdanstatic u_int8_t 11253842Sdanarc4_randbyte(void) 11353842Sdan{ 11453842Sdan u_int8_t arc4_t; 11553842Sdan 11653842Sdan arc4_i = (arc4_i + 1) % 256; 11753842Sdan arc4_j = (arc4_j + arc4_sbox[arc4_i]) % 256; 11853842Sdan 11953842Sdan arc4_swap(&arc4_sbox[arc4_i], &arc4_sbox[arc4_j]); 12053842Sdan 12153842Sdan arc4_t = (arc4_sbox[arc4_i] + arc4_sbox[arc4_j]) % 256; 12253842Sdan return arc4_sbox[arc4_t]; 12353842Sdan} 12453842Sdan 125118938Ssilby/* 126118938Ssilby * MPSAFE 127118938Ssilby */ 128104900Sphkvoid 129104900Sphkarc4rand(void *ptr, u_int len, int reseed) 13053842Sdan{ 131104900Sphk u_char *p; 132104900Sphk struct timeval tv; 13353842Sdan 134104900Sphk getmicrouptime(&tv); 135249631Sache if (atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_HAVE, 136249631Sache ARC4_ENTR_SEED) || reseed || 137104900Sphk (arc4_numruns > ARC4_RESEED_BYTES) || 138104900Sphk (tv.tv_sec > arc4_t_reseed)) 13953864Sdan arc4_randomstir(); 14053842Sdan 141118938Ssilby mtx_lock(&arc4_mtx); 142118938Ssilby arc4_numruns += len; 143104900Sphk p = ptr; 144104900Sphk while (len--) 145104900Sphk *p++ = arc4_randbyte(); 146118938Ssilby mtx_unlock(&arc4_mtx); 147104900Sphk} 14853842Sdan 149104900Sphkuint32_t 150104900Sphkarc4random(void) 151104900Sphk{ 152104900Sphk uint32_t ret; 153104900Sphk 154104900Sphk arc4rand(&ret, sizeof ret, 0); 15553842Sdan return ret; 15653842Sdan} 157