1 /* $MirOS: src/sys/crypto/arc4random.c,v 1.8 2014/03/13 06:09:48 tg Exp $ */
2
3 /*-
4 * Copyright © 2010, 2014
5 * Thorsten Glaser <tg@mirbsd.org>
6 *
7 * Provided that these terms and disclaimer and all copyright notices
8 * are retained or reproduced in an accompanying document, permission
9 * is granted to deal in this work without restriction, including un‐
10 * limited rights to use, publicly perform, distribute, sell, modify,
11 * merge, give away, or sublicence.
12 *
13 * This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
14 * the utmost extent permitted by applicable law, neither express nor
15 * implied; without malicious intent or gross negligence. In no event
16 * may a licensor, author or contributor be held liable for indirect,
17 * direct, other damage, loss, or other issues arising in any way out
18 * of dealing in the work, even if advised of the possibility of such
19 * damage or existence of a defect, except proven that it results out
20 * of said person’s immediate fault when using the work as intended.
21 *-
22 * Always working arc4random(9) implementation; the arcfour state has
23 * been initialised at kernel compile time by newvers.sh for us. Once
24 * the random device has attached, arc4random_reinit() will be called
25 * from a timeout, or when enough bytes are consumed, and restir with
26 * entropy from both the rndpool and the lopool.
27 */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/timeout.h>
33 #include <crypto/randimpl.h>
34
35 /* import from random.c */
36 extern struct timeout arc4random_timeout;
37 extern struct arcfour_status lopool_collapse;
38
39 /* import from vers.c generated by conf/newvers.sh */
40 extern struct arcfour_status initial_arc4random;
41
42 size_t arc4random_count = 0;
43
44 /*
45 * 8 MiB seems like a sane limit to protect against reading
46 * enough stream cipher output to try and attack the key
47 */
48 #ifndef ARC4RANDOM_MAXBYTES
49 #define ARC4RANDOM_MAXBYTES (8 * 1048576)
50 #endif
51
52 u_int32_t
arc4random(void)53 arc4random(void)
54 {
55 uint32_t v;
56 int s;
57
58 s = splhigh();
59
60 rndstats.arc4_reads += 4;
61 if (arc4random_count >= ARC4RANDOM_MAXBYTES - 4)
62 arc4random_reinit(NULL);
63 arc4random_count += 4;
64
65 /* skip an output byte randomly for whitening */
66 if ((arcfour_byte(&lopool_collapse) & 1))
67 (void)arcfour_byte(&initial_arc4random);
68
69 v = ((uint32_t)arcfour_byte(&initial_arc4random) << 24) |
70 ((uint32_t)arcfour_byte(&initial_arc4random) << 16) |
71 ((uint32_t)arcfour_byte(&initial_arc4random) << 8) |
72 ((uint32_t)arcfour_byte(&initial_arc4random));
73
74 splx(s);
75 return (v);
76 }
77
78 void
arc4random_buf(void * buf_,size_t len)79 arc4random_buf(void *buf_, size_t len)
80 {
81 size_t n;
82 uint8_t *buf = (uint8_t *)buf_;
83 int s;
84
85 if (!len)
86 return;
87 s = splhigh();
88 rndstats.arc4_reads += len;
89 goto into_the_loop;
90
91 /* operate in chunks of 256 output bytes to give interrupts a chance */
92 while (len) {
93 s = splhigh();
94 into_the_loop:
95 /* skip a few output bytes randomly for whitening */
96 n = arcfour_byte(&lopool_collapse) & 3;
97 while (n--)
98 (void)arcfour_byte(&initial_arc4random);
99
100 n = min(len, 256);
101 len -= n;
102
103 /*
104 * using 256 here, not n, to speed up; the difference
105 * is not worth mentioning, and it’s also more secure
106 */
107 if (arc4random_count >= (ARC4RANDOM_MAXBYTES - 256))
108 arc4random_reinit(NULL);
109 arc4random_count += n;
110
111 while (n--)
112 *buf++ = arcfour_byte(&initial_arc4random);
113
114 splx(s);
115 }
116 }
117
118 /*
119 * Stir the arcfour state used by arc4random(9). This function is
120 * called via a periodic timeout (approximately every 8½ minutes)
121 * as well as from a consumer when approx. 8 MiB were used up.
122 */
123 void
arc4random_reinit(void * arg __unused)124 arc4random_reinit(void *arg __unused)
125 {
126 size_t n;
127 struct {
128 uint8_t chars[192];
129 struct timeval tv;
130 } buf;
131 int s;
132
133 s = splhigh();
134
135 if (!rnd_attached) {
136 RNDEBUG(RD_ALWAYS, "rnd: reinit before attach\n");
137 goto out;
138 }
139
140 /* if we were called directly instead of from timeout */
141 timeout_del(&arc4random_timeout);
142
143 /* half the poolbits, minimum 8, maximum 128 bytes */
144 n = max(8, min(128, (random_state.entropy_count / 16)));
145 rndstats.arc4_stirs += n;
146
147 RNDEBUG(RD_ARC4RANDOM, "rnd: reinit at %lu with %lu bytes\n",
148 (u_long)arc4random_count, (u_long)n);
149 get_random_bytes(buf.chars, n);
150
151 while (n < 192)
152 buf.chars[n++] = arcfour_byte(&lopool_collapse);
153 buf.tv.tv_sec = mono_time.tv_sec;
154 buf.tv.tv_usec = mono_time.tv_usec;
155 /* carry over */
156 n = arcfour_byte(&initial_arc4random) & 7;
157 /* re-key */
158 arcfour_ksa(&initial_arc4random, (void *)&buf, sizeof(buf));
159 arc4random_count = 0;
160 ++rndstats.arc4_nstirs;
161
162 /*
163 * skip early keystream for security,
164 * plus a random amount for whitening
165 */
166 n += 256 * 12 +
167 (arcfour_byte(&lopool_collapse) & 7) +
168 (arcfour_byte(&initial_arc4random) & 7);
169 while (n--)
170 (void)arcfour_byte(&initial_arc4random);
171
172 /* contribute our (lopool,rndpool,arc4pool) result */
173 n = ((uint32_t)arcfour_byte(&initial_arc4random) << 24) |
174 ((uint32_t)arcfour_byte(&initial_arc4random) << 16) |
175 ((uint32_t)arcfour_byte(&initial_arc4random) << 8) |
176 ((uint32_t)arcfour_byte(&initial_arc4random));
177 enqueue_randomness(RND_SRC_LPC, (int)n);
178 n = (arcfour_byte(&initial_arc4random) & 3) +
179 (arcfour_byte(&lopool_collapse) & 3);
180 while (n--)
181 (void)arcfour_byte(&initial_arc4random);
182
183 /* zero out temp. key buffer */
184 bzero(&buf, sizeof(buf));
185
186 /* call us again in approx. 8½ minutes, minus [0‥32[ seconds */
187 timeout_add(&arc4random_timeout,
188 (hz << 9) - arc4random_uniform(hz << 5));
189
190 out:
191 splx(s);
192 }
193