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> 22d65b1670SDan Moschuk 232c38619bSPoul-Henning Kamp #define ARC4_RESEED_BYTES 65536 243a7810bcSMike Silbersack #define ARC4_RESEED_SECONDS 300 252c38619bSPoul-Henning Kamp #define ARC4_KEYBYTES (256 / 8) 26ee3fd601SDan Moschuk 27*2b50ce65SAndrey A. Chernov int arc4rand_iniseed_state = ARC4_ENTR_NONE; 28*2b50ce65SAndrey A. Chernov 29ee3fd601SDan Moschuk static u_int8_t arc4_i, arc4_j; 30d65b1670SDan Moschuk static int arc4_numruns = 0; 31ee3fd601SDan Moschuk static u_int8_t arc4_sbox[256]; 322c38619bSPoul-Henning Kamp static time_t arc4_t_reseed; 332f823fa3SMike Silbersack static struct mtx arc4_mtx; 343a7810bcSMike Silbersack 353a7810bcSMike Silbersack static u_int8_t arc4_randbyte(void); 36ee3fd601SDan Moschuk 37ee3fd601SDan Moschuk static __inline void 38ee3fd601SDan Moschuk arc4_swap(u_int8_t *a, u_int8_t *b) 39ee3fd601SDan Moschuk { 40ee3fd601SDan Moschuk u_int8_t c; 41ee3fd601SDan Moschuk 42ee3fd601SDan Moschuk c = *a; 43ee3fd601SDan Moschuk *a = *b; 44ee3fd601SDan Moschuk *b = c; 45ee3fd601SDan Moschuk } 46ee3fd601SDan Moschuk 47ee3fd601SDan Moschuk /* 48d65b1670SDan Moschuk * Stir our S-box. 49d65b1670SDan Moschuk */ 50d65b1670SDan Moschuk static void 51d65b1670SDan Moschuk arc4_randomstir (void) 52d65b1670SDan Moschuk { 53d65b1670SDan Moschuk u_int8_t key[256]; 54d65b1670SDan Moschuk int r, n; 552c38619bSPoul-Henning Kamp struct timeval tv_now; 56d65b1670SDan Moschuk 5760f8e3afSBruce Evans /* 5860f8e3afSBruce Evans * XXX read_random() returns unsafe numbers if the entropy 5960f8e3afSBruce Evans * device is not loaded -- MarkM. 604cb1e539SMark Murray */ 613a7810bcSMike Silbersack r = read_random(key, ARC4_KEYBYTES); 622f823fa3SMike Silbersack getmicrouptime(&tv_now); 632f823fa3SMike Silbersack mtx_lock(&arc4_mtx); 6460f8e3afSBruce Evans /* If r == 0 || -1, just use what was on the stack. */ 652c38619bSPoul-Henning Kamp if (r > 0) { 66d65b1670SDan Moschuk for (n = r; n < sizeof(key); n++) 67d65b1670SDan Moschuk key[n] = key[n % r]; 68e6082d19SDan Moschuk } 69d65b1670SDan Moschuk 702c38619bSPoul-Henning Kamp for (n = 0; n < 256; n++) { 71d65b1670SDan Moschuk arc4_j = (arc4_j + arc4_sbox[n] + key[n]) % 256; 72d65b1670SDan Moschuk arc4_swap(&arc4_sbox[n], &arc4_sbox[arc4_j]); 73d65b1670SDan Moschuk } 74b834665cSAndrey A. Chernov arc4_i = arc4_j = 0; 753a7810bcSMike Silbersack 763a7810bcSMike Silbersack /* Reset for next reseed cycle. */ 772c38619bSPoul-Henning Kamp arc4_t_reseed = tv_now.tv_sec + ARC4_RESEED_SECONDS; 783a7810bcSMike Silbersack arc4_numruns = 0; 792f823fa3SMike Silbersack 802f823fa3SMike Silbersack /* 81fff6495eSAndrey A. Chernov * Throw away the first N words of output, as suggested in the 822f823fa3SMike Silbersack * paper "Weaknesses in the Key Scheduling Algorithm of RC4" 83fff6495eSAndrey A. Chernov * by Fluher, Mantin, and Shamir. (N = 256 in our case.) 842f823fa3SMike Silbersack */ 85fff6495eSAndrey A. Chernov for (n = 0; n < 256*4; n++) 86fff6495eSAndrey A. Chernov arc4_randbyte(); 872f823fa3SMike Silbersack mtx_unlock(&arc4_mtx); 88d65b1670SDan Moschuk } 89d65b1670SDan Moschuk 90d65b1670SDan Moschuk /* 91ee3fd601SDan Moschuk * Initialize our S-box to its beginning defaults. 92ee3fd601SDan Moschuk */ 93ee3fd601SDan Moschuk static void 94ee3fd601SDan Moschuk arc4_init(void) 95ee3fd601SDan Moschuk { 96ee3fd601SDan Moschuk int n; 97ee3fd601SDan Moschuk 982f823fa3SMike Silbersack mtx_init(&arc4_mtx, "arc4_mtx", NULL, MTX_DEF); 99ee3fd601SDan Moschuk arc4_i = arc4_j = 0; 100ee3fd601SDan Moschuk for (n = 0; n < 256; n++) 101d65b1670SDan Moschuk arc4_sbox[n] = (u_int8_t) n; 102d65b1670SDan Moschuk 1032f823fa3SMike Silbersack arc4_t_reseed = 0; 104ee3fd601SDan Moschuk } 105ee3fd601SDan Moschuk 1062f823fa3SMike Silbersack SYSINIT(arc4_init, SI_SUB_LOCK, SI_ORDER_ANY, arc4_init, NULL); 1072f823fa3SMike Silbersack 108ee3fd601SDan Moschuk /* 109ee3fd601SDan Moschuk * Generate a random byte. 110ee3fd601SDan Moschuk */ 111ee3fd601SDan Moschuk static u_int8_t 112ee3fd601SDan Moschuk arc4_randbyte(void) 113ee3fd601SDan Moschuk { 114ee3fd601SDan Moschuk u_int8_t arc4_t; 115ee3fd601SDan Moschuk 116ee3fd601SDan Moschuk arc4_i = (arc4_i + 1) % 256; 117ee3fd601SDan Moschuk arc4_j = (arc4_j + arc4_sbox[arc4_i]) % 256; 118ee3fd601SDan Moschuk 119ee3fd601SDan Moschuk arc4_swap(&arc4_sbox[arc4_i], &arc4_sbox[arc4_j]); 120ee3fd601SDan Moschuk 121ee3fd601SDan Moschuk arc4_t = (arc4_sbox[arc4_i] + arc4_sbox[arc4_j]) % 256; 122ee3fd601SDan Moschuk return arc4_sbox[arc4_t]; 123ee3fd601SDan Moschuk } 124ee3fd601SDan Moschuk 1252f823fa3SMike Silbersack /* 1262f823fa3SMike Silbersack * MPSAFE 1272f823fa3SMike Silbersack */ 1282c38619bSPoul-Henning Kamp void 1292c38619bSPoul-Henning Kamp arc4rand(void *ptr, u_int len, int reseed) 130ee3fd601SDan Moschuk { 1312c38619bSPoul-Henning Kamp u_char *p; 1322c38619bSPoul-Henning Kamp struct timeval tv; 133ee3fd601SDan Moschuk 1342c38619bSPoul-Henning Kamp getmicrouptime(&tv); 135*2b50ce65SAndrey A. Chernov if (atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_HAVE, 136*2b50ce65SAndrey A. Chernov ARC4_ENTR_SEED) || reseed || 1372c38619bSPoul-Henning Kamp (arc4_numruns > ARC4_RESEED_BYTES) || 1382c38619bSPoul-Henning Kamp (tv.tv_sec > arc4_t_reseed)) 139d65b1670SDan Moschuk arc4_randomstir(); 1402c38619bSPoul-Henning Kamp 1412f823fa3SMike Silbersack mtx_lock(&arc4_mtx); 1422f823fa3SMike Silbersack arc4_numruns += len; 1432c38619bSPoul-Henning Kamp p = ptr; 1442c38619bSPoul-Henning Kamp while (len--) 1452c38619bSPoul-Henning Kamp *p++ = arc4_randbyte(); 1462f823fa3SMike Silbersack mtx_unlock(&arc4_mtx); 147d65b1670SDan Moschuk } 148ee3fd601SDan Moschuk 1492c38619bSPoul-Henning Kamp uint32_t 1502c38619bSPoul-Henning Kamp arc4random(void) 1512c38619bSPoul-Henning Kamp { 1522c38619bSPoul-Henning Kamp uint32_t ret; 153ee3fd601SDan Moschuk 1542c38619bSPoul-Henning Kamp arc4rand(&ret, sizeof ret, 0); 155ee3fd601SDan Moschuk return ret; 156ee3fd601SDan Moschuk } 157