xref: /freebsd/sys/libkern/arc4random.c (revision dcf3302859e24b26f3b1dff2c8e104fdbe976825)
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>
22*dcf33028SFabien Thomas #include <sys/smp.h>
23*dcf33028SFabien Thomas #include <sys/malloc.h>
24d65b1670SDan Moschuk 
252c38619bSPoul-Henning Kamp #define	ARC4_RESEED_BYTES 65536
263a7810bcSMike Silbersack #define	ARC4_RESEED_SECONDS 300
27d1b06863SMark Murray #define	ARC4_KEYBYTES 256
28ee3fd601SDan Moschuk 
292b50ce65SAndrey A. Chernov int arc4rand_iniseed_state = ARC4_ENTR_NONE;
302b50ce65SAndrey A. Chernov 
31*dcf33028SFabien Thomas MALLOC_DEFINE(M_ARC4RANDOM, "arc4random", "arc4random structures");
323a7810bcSMike Silbersack 
33*dcf33028SFabien Thomas struct arc4_s {
34*dcf33028SFabien Thomas 	u_int8_t i, j;
35*dcf33028SFabien Thomas 	int numruns;
36*dcf33028SFabien Thomas 	u_int8_t sbox[256];
37*dcf33028SFabien Thomas 	time_t t_reseed;
38*dcf33028SFabien Thomas 
39*dcf33028SFabien Thomas 	struct mtx mtx;
40*dcf33028SFabien Thomas };
41*dcf33028SFabien Thomas 
42*dcf33028SFabien Thomas static struct arc4_s *arc4inst = NULL;
43*dcf33028SFabien Thomas 
44*dcf33028SFabien Thomas #define ARC4_FOREACH(_arc4) \
45*dcf33028SFabien Thomas 	for (_arc4 = &arc4inst[0]; _arc4 <= &arc4inst[mp_maxid]; _arc4++)
46*dcf33028SFabien Thomas 
47*dcf33028SFabien Thomas static u_int8_t arc4_randbyte(struct arc4_s *arc4);
48ee3fd601SDan Moschuk 
49ee3fd601SDan Moschuk static __inline void
50ee3fd601SDan Moschuk arc4_swap(u_int8_t *a, u_int8_t *b)
51ee3fd601SDan Moschuk {
52ee3fd601SDan Moschuk 	u_int8_t c;
53ee3fd601SDan Moschuk 
54ee3fd601SDan Moschuk 	c = *a;
55ee3fd601SDan Moschuk 	*a = *b;
56ee3fd601SDan Moschuk 	*b = c;
57ee3fd601SDan Moschuk }
58ee3fd601SDan Moschuk 
59ee3fd601SDan Moschuk /*
60d65b1670SDan Moschuk  * Stir our S-box.
61d65b1670SDan Moschuk  */
62d65b1670SDan Moschuk static void
63*dcf33028SFabien Thomas arc4_randomstir(struct arc4_s* arc4)
64d65b1670SDan Moschuk {
65d1b06863SMark Murray 	u_int8_t key[ARC4_KEYBYTES];
66d1b06863SMark Murray 	int n;
672c38619bSPoul-Henning Kamp 	struct timeval tv_now;
68d65b1670SDan Moschuk 
6960f8e3afSBruce Evans 	/*
70d1b06863SMark Murray 	 * XXX: FIX!! This isn't brilliant. Need more confidence.
71d1b06863SMark Murray 	 * This returns zero entropy before random(4) is seeded.
724cb1e539SMark Murray 	 */
73d1b06863SMark Murray 	(void)read_random(key, ARC4_KEYBYTES);
742f823fa3SMike Silbersack 	getmicrouptime(&tv_now);
75*dcf33028SFabien Thomas 	mtx_lock(&arc4->mtx);
762c38619bSPoul-Henning Kamp 	for (n = 0; n < 256; n++) {
77*dcf33028SFabien Thomas 		arc4->j = (arc4->j + arc4->sbox[n] + key[n]) % 256;
78*dcf33028SFabien Thomas 		arc4_swap(&arc4->sbox[n], &arc4->sbox[arc4->j]);
79d65b1670SDan Moschuk 	}
80*dcf33028SFabien Thomas 	arc4->i = arc4->j = 0;
813a7810bcSMike Silbersack 	/* Reset for next reseed cycle. */
82*dcf33028SFabien Thomas 	arc4->t_reseed = tv_now.tv_sec + ARC4_RESEED_SECONDS;
83*dcf33028SFabien Thomas 	arc4->numruns = 0;
842f823fa3SMike Silbersack 	/*
85fff6495eSAndrey A. Chernov 	 * Throw away the first N words of output, as suggested in the
862f823fa3SMike Silbersack 	 * paper "Weaknesses in the Key Scheduling Algorithm of RC4"
87fff6495eSAndrey A. Chernov 	 * by Fluher, Mantin, and Shamir.  (N = 256 in our case.)
88d1b06863SMark Murray 	 *
89d1b06863SMark Murray 	 * http://dl.acm.org/citation.cfm?id=646557.694759
902f823fa3SMike Silbersack 	 */
91fff6495eSAndrey A. Chernov 	for (n = 0; n < 256*4; n++)
92*dcf33028SFabien Thomas 		arc4_randbyte(arc4);
93*dcf33028SFabien Thomas 
94*dcf33028SFabien Thomas 	mtx_unlock(&arc4->mtx);
95d65b1670SDan Moschuk }
96d65b1670SDan Moschuk 
97d65b1670SDan Moschuk /*
98ee3fd601SDan Moschuk  * Initialize our S-box to its beginning defaults.
99ee3fd601SDan Moschuk  */
100ee3fd601SDan Moschuk static void
101ee3fd601SDan Moschuk arc4_init(void)
102ee3fd601SDan Moschuk {
103*dcf33028SFabien Thomas 	struct arc4_s *arc4;
104ee3fd601SDan Moschuk 	int n;
105ee3fd601SDan Moschuk 
106*dcf33028SFabien Thomas 	arc4inst = malloc((mp_maxid + 1) * sizeof(struct arc4_s),
107*dcf33028SFabien Thomas 			M_ARC4RANDOM, M_NOWAIT | M_ZERO);
108*dcf33028SFabien Thomas 	KASSERT(arc4inst != NULL, ("arc4_init: memory allocation error"));
109d65b1670SDan Moschuk 
110*dcf33028SFabien Thomas 	ARC4_FOREACH(arc4) {
111*dcf33028SFabien Thomas 		mtx_init(&arc4->mtx, "arc4_mtx", NULL, MTX_DEF);
112*dcf33028SFabien Thomas 
113*dcf33028SFabien Thomas 		arc4->i = arc4->j = 0;
114*dcf33028SFabien Thomas 		for (n = 0; n < 256; n++)
115*dcf33028SFabien Thomas 			arc4->sbox[n] = (u_int8_t) n;
116*dcf33028SFabien Thomas 
117*dcf33028SFabien Thomas 		arc4->t_reseed = -1;
118*dcf33028SFabien Thomas 		arc4->numruns = 0;
119*dcf33028SFabien Thomas 	}
120*dcf33028SFabien Thomas }
121*dcf33028SFabien Thomas SYSINIT(arc4, SI_SUB_LOCK, SI_ORDER_ANY, arc4_init, NULL);
122*dcf33028SFabien Thomas 
123*dcf33028SFabien Thomas 
124*dcf33028SFabien Thomas static void
125*dcf33028SFabien Thomas arc4_uninit(void)
126*dcf33028SFabien Thomas {
127*dcf33028SFabien Thomas 	struct arc4_s *arc4;
128*dcf33028SFabien Thomas 
129*dcf33028SFabien Thomas 	ARC4_FOREACH(arc4) {
130*dcf33028SFabien Thomas 		mtx_destroy(&arc4->mtx);
131ee3fd601SDan Moschuk 	}
132ee3fd601SDan Moschuk 
133*dcf33028SFabien Thomas 	free(arc4inst, M_ARC4RANDOM);
134*dcf33028SFabien Thomas }
135*dcf33028SFabien Thomas 
136*dcf33028SFabien Thomas SYSUNINIT(arc4, SI_SUB_LOCK, SI_ORDER_ANY, arc4_uninit, NULL);
137*dcf33028SFabien Thomas 
1382f823fa3SMike Silbersack 
139ee3fd601SDan Moschuk /*
140ee3fd601SDan Moschuk  * Generate a random byte.
141ee3fd601SDan Moschuk  */
142ee3fd601SDan Moschuk static u_int8_t
143*dcf33028SFabien Thomas arc4_randbyte(struct arc4_s *arc4)
144ee3fd601SDan Moschuk {
145ee3fd601SDan Moschuk 	u_int8_t arc4_t;
146ee3fd601SDan Moschuk 
147*dcf33028SFabien Thomas 	arc4->i = (arc4->i + 1) % 256;
148*dcf33028SFabien Thomas 	arc4->j = (arc4->j + arc4->sbox[arc4->i]) % 256;
149ee3fd601SDan Moschuk 
150*dcf33028SFabien Thomas 	arc4_swap(&arc4->sbox[arc4->i], &arc4->sbox[arc4->j]);
151ee3fd601SDan Moschuk 
152*dcf33028SFabien Thomas 	arc4_t = (arc4->sbox[arc4->i] + arc4->sbox[arc4->j]) % 256;
153*dcf33028SFabien Thomas 	return arc4->sbox[arc4_t];
154ee3fd601SDan Moschuk }
155ee3fd601SDan Moschuk 
1562f823fa3SMike Silbersack /*
1572f823fa3SMike Silbersack  * MPSAFE
1582f823fa3SMike Silbersack  */
1592c38619bSPoul-Henning Kamp void
1602c38619bSPoul-Henning Kamp arc4rand(void *ptr, u_int len, int reseed)
161ee3fd601SDan Moschuk {
1622c38619bSPoul-Henning Kamp 	u_char *p;
1632c38619bSPoul-Henning Kamp 	struct timeval tv;
164*dcf33028SFabien Thomas 	struct arc4_s *arc4;
165ee3fd601SDan Moschuk 
166*dcf33028SFabien Thomas 	if (reseed || atomic_cmpset_int(&arc4rand_iniseed_state,
167*dcf33028SFabien Thomas 			ARC4_ENTR_HAVE, ARC4_ENTR_SEED)) {
168*dcf33028SFabien Thomas 		ARC4_FOREACH(arc4)
169*dcf33028SFabien Thomas 			arc4_randomstir(arc4);
170*dcf33028SFabien Thomas 	}
171*dcf33028SFabien Thomas 
172*dcf33028SFabien Thomas 	arc4 = &arc4inst[curcpu];
1732c38619bSPoul-Henning Kamp 	getmicrouptime(&tv);
174*dcf33028SFabien Thomas 	if ((arc4->numruns > ARC4_RESEED_BYTES) ||
175*dcf33028SFabien Thomas 		(tv.tv_sec > arc4->t_reseed))
176*dcf33028SFabien Thomas 		arc4_randomstir(arc4);
1772c38619bSPoul-Henning Kamp 
178*dcf33028SFabien Thomas 	mtx_lock(&arc4->mtx);
179*dcf33028SFabien Thomas 	arc4->numruns += len;
1802c38619bSPoul-Henning Kamp 	p = ptr;
1812c38619bSPoul-Henning Kamp 	while (len--)
182*dcf33028SFabien Thomas 		*p++ = arc4_randbyte(arc4);
183*dcf33028SFabien Thomas 	mtx_unlock(&arc4->mtx);
184d65b1670SDan Moschuk }
185ee3fd601SDan Moschuk 
1862c38619bSPoul-Henning Kamp uint32_t
1872c38619bSPoul-Henning Kamp arc4random(void)
1882c38619bSPoul-Henning Kamp {
1892c38619bSPoul-Henning Kamp 	uint32_t ret;
190ee3fd601SDan Moschuk 
1912c38619bSPoul-Henning Kamp 	arc4rand(&ret, sizeof ret, 0);
192ee3fd601SDan Moschuk 	return ret;
193ee3fd601SDan Moschuk }
194