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> 16d65b1670SDan Moschuk 17d65b1670SDan Moschuk #define ARC4_MAXRUNS 64 18ee3fd601SDan Moschuk 19ee3fd601SDan Moschuk static u_int8_t arc4_i, arc4_j; 20ee3fd601SDan Moschuk static int arc4_initialized = 0; 21d65b1670SDan Moschuk static int arc4_numruns = 0; 22ee3fd601SDan Moschuk static u_int8_t arc4_sbox[256]; 23ee3fd601SDan Moschuk 24ee3fd601SDan Moschuk static __inline void 25ee3fd601SDan Moschuk arc4_swap(u_int8_t *a, u_int8_t *b) 26ee3fd601SDan Moschuk { 27ee3fd601SDan Moschuk u_int8_t c; 28ee3fd601SDan Moschuk 29ee3fd601SDan Moschuk c = *a; 30ee3fd601SDan Moschuk *a = *b; 31ee3fd601SDan Moschuk *b = c; 32ee3fd601SDan Moschuk } 33ee3fd601SDan Moschuk 34ee3fd601SDan Moschuk /* 35d65b1670SDan Moschuk * Stir our S-box. 36d65b1670SDan Moschuk */ 37d65b1670SDan Moschuk static void 38d65b1670SDan Moschuk arc4_randomstir (void) 39d65b1670SDan Moschuk { 40d65b1670SDan Moschuk u_int8_t key[256]; 41d65b1670SDan Moschuk int r, n; 42d65b1670SDan Moschuk 434cb1e539SMark Murray /* XXX read_random() returns unsafe numbers if the entropy 444cb1e539SMark Murray * devce is not loaded - MarkM 454cb1e539SMark Murray */ 464cb1e539SMark Murray r = read_random(key, sizeof(key)); 47e6082d19SDan Moschuk /* if r == 0 || -1, just use what was on the stack */ 48e6082d19SDan Moschuk if (r > 0) 49e6082d19SDan Moschuk { 50d65b1670SDan Moschuk for (n = r; n < sizeof(key); n++) 51d65b1670SDan Moschuk key[n] = key[n % r]; 52e6082d19SDan Moschuk } 53d65b1670SDan Moschuk 54d65b1670SDan Moschuk for (n = 0; n < 256; n++) 55d65b1670SDan Moschuk { 56d65b1670SDan Moschuk arc4_j = (arc4_j + arc4_sbox[n] + key[n]) % 256; 57d65b1670SDan Moschuk arc4_swap(&arc4_sbox[n], &arc4_sbox[arc4_j]); 58d65b1670SDan Moschuk } 59d65b1670SDan Moschuk } 60d65b1670SDan Moschuk 61d65b1670SDan Moschuk /* 62ee3fd601SDan Moschuk * Initialize our S-box to its beginning defaults. 63ee3fd601SDan Moschuk */ 64ee3fd601SDan Moschuk static void 65ee3fd601SDan Moschuk arc4_init(void) 66ee3fd601SDan Moschuk { 67ee3fd601SDan Moschuk int n; 68ee3fd601SDan Moschuk 69ee3fd601SDan Moschuk arc4_i = arc4_j = 0; 70ee3fd601SDan Moschuk for (n = 0; n < 256; n++) 71d65b1670SDan Moschuk arc4_sbox[n] = (u_int8_t) n; 72d65b1670SDan Moschuk 73d65b1670SDan Moschuk arc4_randomstir(); 74ee3fd601SDan Moschuk arc4_initialized = 1; 75ee3fd601SDan Moschuk } 76ee3fd601SDan Moschuk 77ee3fd601SDan Moschuk /* 78ee3fd601SDan Moschuk * Generate a random byte. 79ee3fd601SDan Moschuk */ 80ee3fd601SDan Moschuk static u_int8_t 81ee3fd601SDan Moschuk arc4_randbyte(void) 82ee3fd601SDan Moschuk { 83ee3fd601SDan Moschuk u_int8_t arc4_t; 84ee3fd601SDan Moschuk 85ee3fd601SDan Moschuk arc4_i = (arc4_i + 1) % 256; 86ee3fd601SDan Moschuk arc4_j = (arc4_j + arc4_sbox[arc4_i]) % 256; 87ee3fd601SDan Moschuk 88ee3fd601SDan Moschuk arc4_swap(&arc4_sbox[arc4_i], &arc4_sbox[arc4_j]); 89ee3fd601SDan Moschuk 90ee3fd601SDan Moschuk arc4_t = (arc4_sbox[arc4_i] + arc4_sbox[arc4_j]) % 256; 91ee3fd601SDan Moschuk return arc4_sbox[arc4_t]; 92ee3fd601SDan Moschuk } 93ee3fd601SDan Moschuk 94ee3fd601SDan Moschuk u_int32_t 95ee3fd601SDan Moschuk arc4random(void) 96ee3fd601SDan Moschuk { 97ee3fd601SDan Moschuk u_int32_t ret; 98ee3fd601SDan Moschuk 99ee3fd601SDan Moschuk /* Initialize array if needed. */ 100ee3fd601SDan Moschuk if (!arc4_initialized) 101ee3fd601SDan Moschuk arc4_init(); 102d65b1670SDan Moschuk if (++arc4_numruns > ARC4_MAXRUNS) 103d65b1670SDan Moschuk { 104d65b1670SDan Moschuk arc4_randomstir(); 105d65b1670SDan Moschuk arc4_numruns = 0; 106d65b1670SDan Moschuk } 107ee3fd601SDan Moschuk 108ee3fd601SDan Moschuk ret = arc4_randbyte(); 109ee3fd601SDan Moschuk ret |= arc4_randbyte() << 8; 110ee3fd601SDan Moschuk ret |= arc4_randbyte() << 16; 111ee3fd601SDan Moschuk ret |= arc4_randbyte() << 24; 112ee3fd601SDan Moschuk 113ee3fd601SDan Moschuk return ret; 114ee3fd601SDan Moschuk } 115