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 * $FreeBSD$ 11ee3fd601SDan Moschuk */ 12ee3fd601SDan Moschuk 13bf3191e9SMark Murray #include <sys/types.h> 14bf3191e9SMark Murray #include <sys/random.h> 15ee3fd601SDan Moschuk #include <sys/libkern.h> 163a7810bcSMike Silbersack #include <sys/time.h> 17d65b1670SDan Moschuk 183a7810bcSMike Silbersack #define ARC4_MAXRUNS 16384 193a7810bcSMike Silbersack #define ARC4_RESEED_SECONDS 300 203a7810bcSMike Silbersack #define ARC4_KEYBYTES 32 /* 256 bit key */ 21ee3fd601SDan Moschuk 22ee3fd601SDan Moschuk static u_int8_t arc4_i, arc4_j; 23ee3fd601SDan Moschuk static int arc4_initialized = 0; 24d65b1670SDan Moschuk static int arc4_numruns = 0; 25ee3fd601SDan Moschuk static u_int8_t arc4_sbox[256]; 263a7810bcSMike Silbersack static struct timeval arc4_tv_nextreseed; 273a7810bcSMike Silbersack 283a7810bcSMike Silbersack static u_int8_t arc4_randbyte(void); 29ee3fd601SDan Moschuk 30ee3fd601SDan Moschuk static __inline void 31ee3fd601SDan Moschuk arc4_swap(u_int8_t *a, u_int8_t *b) 32ee3fd601SDan Moschuk { 33ee3fd601SDan Moschuk u_int8_t c; 34ee3fd601SDan Moschuk 35ee3fd601SDan Moschuk c = *a; 36ee3fd601SDan Moschuk *a = *b; 37ee3fd601SDan Moschuk *b = c; 38ee3fd601SDan Moschuk } 39ee3fd601SDan Moschuk 40ee3fd601SDan Moschuk /* 41d65b1670SDan Moschuk * Stir our S-box. 42d65b1670SDan Moschuk */ 43d65b1670SDan Moschuk static void 44d65b1670SDan Moschuk arc4_randomstir (void) 45d65b1670SDan Moschuk { 46d65b1670SDan Moschuk u_int8_t key[256]; 47d65b1670SDan Moschuk int r, n; 48d65b1670SDan Moschuk 494cb1e539SMark Murray /* XXX read_random() returns unsafe numbers if the entropy 504cb1e539SMark Murray * devce is not loaded - MarkM 514cb1e539SMark Murray */ 523a7810bcSMike Silbersack r = read_random(key, ARC4_KEYBYTES); 53e6082d19SDan Moschuk /* if r == 0 || -1, just use what was on the stack */ 54e6082d19SDan Moschuk if (r > 0) 55e6082d19SDan Moschuk { 56d65b1670SDan Moschuk for (n = r; n < sizeof(key); n++) 57d65b1670SDan Moschuk key[n] = key[n % r]; 58e6082d19SDan Moschuk } 59d65b1670SDan Moschuk 60d65b1670SDan Moschuk for (n = 0; n < 256; n++) 61d65b1670SDan Moschuk { 62d65b1670SDan Moschuk arc4_j = (arc4_j + arc4_sbox[n] + key[n]) % 256; 63d65b1670SDan Moschuk arc4_swap(&arc4_sbox[n], &arc4_sbox[arc4_j]); 64d65b1670SDan Moschuk } 653a7810bcSMike Silbersack 663a7810bcSMike Silbersack /* Reset for next reseed cycle. */ 673a7810bcSMike Silbersack getmicrotime(&arc4_tv_nextreseed); 683a7810bcSMike Silbersack arc4_tv_nextreseed.tv_sec += ARC4_RESEED_SECONDS; 693a7810bcSMike Silbersack arc4_numruns = 0; 70d65b1670SDan Moschuk } 71d65b1670SDan Moschuk 72d65b1670SDan Moschuk /* 73ee3fd601SDan Moschuk * Initialize our S-box to its beginning defaults. 74ee3fd601SDan Moschuk */ 75ee3fd601SDan Moschuk static void 76ee3fd601SDan Moschuk arc4_init(void) 77ee3fd601SDan Moschuk { 78ee3fd601SDan Moschuk int n; 79ee3fd601SDan Moschuk 80ee3fd601SDan Moschuk arc4_i = arc4_j = 0; 81ee3fd601SDan Moschuk for (n = 0; n < 256; n++) 82d65b1670SDan Moschuk arc4_sbox[n] = (u_int8_t) n; 83d65b1670SDan Moschuk 84d65b1670SDan Moschuk arc4_randomstir(); 85ee3fd601SDan Moschuk arc4_initialized = 1; 863a7810bcSMike Silbersack 873a7810bcSMike Silbersack /* Now, throw away the first N words out output, as suggested 883a7810bcSMike Silbersack * in the paper "Weaknesses in the Key Scheduling Algorithm 893a7810bcSMike Silbersack * of RC4" by Fluher, Mantin, and Shamir. 903a7810bcSMike Silbersack * 913a7810bcSMike Silbersack * (N = 256 in our case.) 923a7810bcSMike Silbersack */ 933a7810bcSMike Silbersack for (n = 0; n < 256*4; n++) 943a7810bcSMike Silbersack arc4_randbyte(); 95ee3fd601SDan Moschuk } 96ee3fd601SDan Moschuk 97ee3fd601SDan Moschuk /* 98ee3fd601SDan Moschuk * Generate a random byte. 99ee3fd601SDan Moschuk */ 100ee3fd601SDan Moschuk static u_int8_t 101ee3fd601SDan Moschuk arc4_randbyte(void) 102ee3fd601SDan Moschuk { 103ee3fd601SDan Moschuk u_int8_t arc4_t; 104ee3fd601SDan Moschuk 105ee3fd601SDan Moschuk arc4_i = (arc4_i + 1) % 256; 106ee3fd601SDan Moschuk arc4_j = (arc4_j + arc4_sbox[arc4_i]) % 256; 107ee3fd601SDan Moschuk 108ee3fd601SDan Moschuk arc4_swap(&arc4_sbox[arc4_i], &arc4_sbox[arc4_j]); 109ee3fd601SDan Moschuk 110ee3fd601SDan Moschuk arc4_t = (arc4_sbox[arc4_i] + arc4_sbox[arc4_j]) % 256; 111ee3fd601SDan Moschuk return arc4_sbox[arc4_t]; 112ee3fd601SDan Moschuk } 113ee3fd601SDan Moschuk 114ee3fd601SDan Moschuk u_int32_t 115ee3fd601SDan Moschuk arc4random(void) 116ee3fd601SDan Moschuk { 117ee3fd601SDan Moschuk u_int32_t ret; 1183a7810bcSMike Silbersack struct timeval tv_now; 119ee3fd601SDan Moschuk 120ee3fd601SDan Moschuk /* Initialize array if needed. */ 121ee3fd601SDan Moschuk if (!arc4_initialized) 122ee3fd601SDan Moschuk arc4_init(); 1233a7810bcSMike Silbersack 1243a7810bcSMike Silbersack /* Get current time. */ 1253a7810bcSMike Silbersack getmicrotime(&tv_now); 1263a7810bcSMike Silbersack 1273a7810bcSMike Silbersack if ((++arc4_numruns > ARC4_MAXRUNS) || 1283a7810bcSMike Silbersack (tv_now.tv_sec > arc4_tv_nextreseed.tv_sec)) 129d65b1670SDan Moschuk { 130d65b1670SDan Moschuk arc4_randomstir(); 131d65b1670SDan Moschuk } 132ee3fd601SDan Moschuk 133ee3fd601SDan Moschuk ret = arc4_randbyte(); 134ee3fd601SDan Moschuk ret |= arc4_randbyte() << 8; 135ee3fd601SDan Moschuk ret |= arc4_randbyte() << 16; 136ee3fd601SDan Moschuk ret |= arc4_randbyte() << 24; 137ee3fd601SDan Moschuk 138ee3fd601SDan Moschuk return ret; 139ee3fd601SDan Moschuk } 140