xref: /freebsd/sys/libkern/arc4random.c (revision ee3fd60126538da89df815fb30cd5230eee368e0)
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 
13ee3fd601SDan Moschuk #include <sys/libkern.h>
14ee3fd601SDan Moschuk #include <sys/time.h>
15ee3fd601SDan Moschuk 
16ee3fd601SDan Moschuk static u_int8_t arc4_i, arc4_j;
17ee3fd601SDan Moschuk static int arc4_initialized = 0;
18ee3fd601SDan Moschuk static u_int8_t arc4_sbox[256];
19ee3fd601SDan Moschuk 
20ee3fd601SDan Moschuk static __inline void
21ee3fd601SDan Moschuk arc4_swap(u_int8_t *a, u_int8_t *b)
22ee3fd601SDan Moschuk {
23ee3fd601SDan Moschuk 	u_int8_t c;
24ee3fd601SDan Moschuk 
25ee3fd601SDan Moschuk 	c = *a;
26ee3fd601SDan Moschuk 	*a = *b;
27ee3fd601SDan Moschuk 	*b = c;
28ee3fd601SDan Moschuk }
29ee3fd601SDan Moschuk 
30ee3fd601SDan Moschuk /*
31ee3fd601SDan Moschuk  * Initialize our S-box to its beginning defaults.
32ee3fd601SDan Moschuk  */
33ee3fd601SDan Moschuk static void
34ee3fd601SDan Moschuk arc4_init(void)
35ee3fd601SDan Moschuk {
36ee3fd601SDan Moschuk 	struct timespec ts;
37ee3fd601SDan Moschuk 	u_int8_t key[256];
38ee3fd601SDan Moschuk 	int n;
39ee3fd601SDan Moschuk 
40ee3fd601SDan Moschuk 	for (n = 0; n < 256; n++)
41ee3fd601SDan Moschuk 		arc4_sbox[n] = (u_int8_t) n;
42ee3fd601SDan Moschuk 
43ee3fd601SDan Moschuk 	nanotime(&ts);
44ee3fd601SDan Moschuk 	srandom(ts.tv_sec ^ ts.tv_nsec);
45ee3fd601SDan Moschuk 	for (n = 0; n < 256; n++)
46ee3fd601SDan Moschuk 		key[n] = random() % 256;
47ee3fd601SDan Moschuk 
48ee3fd601SDan Moschuk 	arc4_i = arc4_j = 0;
49ee3fd601SDan Moschuk 	for (n = 0; n < 256; n++)
50ee3fd601SDan Moschuk 	{
51ee3fd601SDan Moschuk 		arc4_j = arc4_j + arc4_sbox[n] + key[n];
52ee3fd601SDan Moschuk 		arc4_swap(&arc4_sbox[n], &arc4_sbox[arc4_j]);
53ee3fd601SDan Moschuk 	}
54ee3fd601SDan Moschuk 	arc4_initialized = 1;
55ee3fd601SDan Moschuk }
56ee3fd601SDan Moschuk 
57ee3fd601SDan Moschuk /*
58ee3fd601SDan Moschuk  * Generate a random byte.
59ee3fd601SDan Moschuk  */
60ee3fd601SDan Moschuk static u_int8_t
61ee3fd601SDan Moschuk arc4_randbyte(void)
62ee3fd601SDan Moschuk {
63ee3fd601SDan Moschuk 	u_int8_t arc4_t;
64ee3fd601SDan Moschuk 
65ee3fd601SDan Moschuk 	arc4_i = (arc4_i + 1) % 256;
66ee3fd601SDan Moschuk 	arc4_j = (arc4_j + arc4_sbox[arc4_i]) % 256;
67ee3fd601SDan Moschuk 
68ee3fd601SDan Moschuk 	arc4_swap(&arc4_sbox[arc4_i], &arc4_sbox[arc4_j]);
69ee3fd601SDan Moschuk 
70ee3fd601SDan Moschuk 	arc4_t = (arc4_sbox[arc4_i] + arc4_sbox[arc4_j]) % 256;
71ee3fd601SDan Moschuk 	return arc4_sbox[arc4_t];
72ee3fd601SDan Moschuk }
73ee3fd601SDan Moschuk 
74ee3fd601SDan Moschuk u_int32_t
75ee3fd601SDan Moschuk arc4random(void)
76ee3fd601SDan Moschuk {
77ee3fd601SDan Moschuk 	u_int32_t ret;
78ee3fd601SDan Moschuk 
79ee3fd601SDan Moschuk 	/* Initialize array if needed. */
80ee3fd601SDan Moschuk 	if (!arc4_initialized)
81ee3fd601SDan Moschuk 		arc4_init();
82ee3fd601SDan Moschuk 
83ee3fd601SDan Moschuk 	ret = arc4_randbyte();
84ee3fd601SDan Moschuk 	ret |= arc4_randbyte() << 8;
85ee3fd601SDan Moschuk 	ret |= arc4_randbyte() << 16;
86ee3fd601SDan Moschuk 	ret |= arc4_randbyte() << 24;
87ee3fd601SDan Moschuk 
88ee3fd601SDan Moschuk 	return ret;
89ee3fd601SDan Moschuk }
90