]>
Commit | Line | Data |
---|---|---|
5b2abdfb | 1 | /* |
1f2f436a A |
2 | * Copyright (c) 1996, David Mazieres <dm@uun.org> |
3 | * Copyright (c) 2008, Damien Miller <djm@openbsd.org> | |
4 | * | |
5 | * Permission to use, copy, modify, and distribute this software for any | |
6 | * purpose with or without fee is hereby granted, provided that the above | |
7 | * copyright notice and this permission notice appear in all copies. | |
5b2abdfb | 8 | * |
1f2f436a A |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
5b2abdfb A |
16 | */ |
17 | ||
18 | /* | |
1f2f436a A |
19 | * Arc4 random number generator for OpenBSD. |
20 | * | |
5b2abdfb A |
21 | * This code is derived from section 17.1 of Applied Cryptography, |
22 | * second edition, which describes a stream cipher allegedly | |
23 | * compatible with RSA Labs "RC4" cipher (the actual description of | |
24 | * which is a trade secret). The same algorithm is used as a stream | |
25 | * cipher called "arcfour" in Tatu Ylonen's ssh package. | |
26 | * | |
27 | * Here the stream cipher has been modified always to include the time | |
28 | * when initializing the state. That makes it impossible to | |
29 | * regenerate the same random sequence twice, so this can't be used | |
30 | * for encryption, but will generate good random numbers. | |
31 | * | |
32 | * RC4 is a registered trademark of RSA Laboratories. | |
33 | */ | |
34 | ||
224c7076 | 35 | #include <sys/cdefs.h> |
1f2f436a | 36 | __FBSDID("$FreeBSD: src/lib/libc/gen/arc4random.c,v 1.25 2008/09/09 09:46:36 ache Exp $"); |
224c7076 A |
37 | |
38 | #include "namespace.h" | |
39 | #include <sys/types.h> | |
40 | #include <sys/time.h> | |
5b2abdfb A |
41 | #include <stdlib.h> |
42 | #include <fcntl.h> | |
43 | #include <unistd.h> | |
224c7076 A |
44 | #include <pthread.h> |
45 | ||
46 | #include "libc_private.h" | |
47 | #include "un-namespace.h" | |
5b2abdfb A |
48 | |
49 | struct arc4_stream { | |
50 | u_int8_t i; | |
51 | u_int8_t j; | |
52 | u_int8_t s[256]; | |
53 | }; | |
54 | ||
1f2f436a A |
55 | static int lock = 0; |
56 | extern void spin_lock(int*); | |
57 | extern void spin_unlock(int*); | |
224c7076 | 58 | |
1f2f436a A |
59 | #define RANDOMDEV "/dev/random" |
60 | #define KEYSIZE 128 | |
224c7076 A |
61 | #define THREAD_LOCK() \ |
62 | do { \ | |
63 | if (__isthreaded) \ | |
1f2f436a | 64 | spin_lock(&lock); \ |
224c7076 A |
65 | } while (0) |
66 | ||
67 | #define THREAD_UNLOCK() \ | |
68 | do { \ | |
69 | if (__isthreaded) \ | |
1f2f436a | 70 | spin_unlock(&lock); \ |
224c7076 A |
71 | } while (0) |
72 | ||
1f2f436a A |
73 | static struct arc4_stream rs = { |
74 | .i = 0, | |
75 | .j = 0, | |
76 | .s = { | |
77 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, | |
78 | 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | |
79 | 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, | |
80 | 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, | |
81 | 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, | |
82 | 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, | |
83 | 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, | |
84 | 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, | |
85 | 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, | |
86 | 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, | |
87 | 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, | |
88 | 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, | |
89 | 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, | |
90 | 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, | |
91 | 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, | |
92 | 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 | |
93 | } | |
94 | }; | |
224c7076 | 95 | static int rs_stired; |
1f2f436a | 96 | static int arc4_count; |
224c7076 | 97 | |
1f2f436a A |
98 | static inline u_int8_t arc4_getbyte(void); |
99 | static void arc4_stir(void); | |
5b2abdfb | 100 | |
1f2f436a A |
101 | static struct { |
102 | struct timeval tv; | |
103 | pid_t pid; | |
104 | u_int8_t rnd[KEYSIZE]; | |
105 | } rdat; | |
106 | static volatile int rs_data_available = 0; | |
5b2abdfb A |
107 | |
108 | static inline void | |
1f2f436a | 109 | arc4_addrandom(u_char *dat, int datlen) |
5b2abdfb A |
110 | { |
111 | int n; | |
112 | u_int8_t si; | |
113 | ||
1f2f436a | 114 | rs.i--; |
5b2abdfb | 115 | for (n = 0; n < 256; n++) { |
1f2f436a A |
116 | rs.i = (rs.i + 1); |
117 | si = rs.s[rs.i]; | |
118 | rs.j = (rs.j + si + dat[n % datlen]); | |
119 | rs.s[rs.i] = rs.s[rs.j]; | |
120 | rs.s[rs.j] = si; | |
5b2abdfb | 121 | } |
1f2f436a | 122 | rs.j = rs.i; |
5b2abdfb A |
123 | } |
124 | ||
125 | static void | |
1f2f436a | 126 | arc4_fetch(void) |
5b2abdfb | 127 | { |
1f2f436a | 128 | int done, fd; |
224c7076 | 129 | fd = _open(RANDOMDEV, O_RDONLY, 0); |
1f2f436a | 130 | done = 0; |
5b2abdfb | 131 | if (fd >= 0) { |
1f2f436a A |
132 | if (_read(fd, &rdat, KEYSIZE) == KEYSIZE) |
133 | done = 1; | |
134 | (void)_close(fd); | |
224c7076 | 135 | } |
1f2f436a A |
136 | if (!done) { |
137 | (void)gettimeofday(&rdat.tv, NULL); | |
138 | rdat.pid = getpid(); | |
139 | /* We'll just take whatever was on the stack too... */ | |
140 | } | |
141 | } | |
5b2abdfb | 142 | |
1f2f436a A |
143 | static void |
144 | arc4_stir(void) | |
145 | { | |
146 | int n; | |
147 | /* | |
148 | * If we don't have data, we need some now before we can integrate | |
149 | * it into the static buffers | |
150 | */ | |
151 | if (!rs_data_available) | |
152 | { | |
153 | arc4_fetch(); | |
154 | } | |
155 | rs_data_available = 0; | |
156 | __sync_synchronize(); | |
157 | ||
158 | arc4_addrandom((u_char *)&rdat, KEYSIZE); | |
224c7076 A |
159 | |
160 | /* | |
161 | * Throw away the first N bytes of output, as suggested in the | |
162 | * paper "Weaknesses in the Key Scheduling Algorithm of RC4" | |
163 | * by Fluher, Mantin, and Shamir. N=1024 is based on | |
164 | * suggestions in the paper "(Not So) Random Shuffles of RC4" | |
165 | * by Ilya Mironov. | |
166 | */ | |
167 | for (n = 0; n < 1024; n++) | |
1f2f436a A |
168 | (void) arc4_getbyte(); |
169 | arc4_count = 1600000; | |
170 | rs_stired = 1; | |
5b2abdfb A |
171 | } |
172 | ||
173 | static inline u_int8_t | |
1f2f436a | 174 | arc4_getbyte(void) |
5b2abdfb A |
175 | { |
176 | u_int8_t si, sj; | |
177 | ||
1f2f436a A |
178 | rs.i = (rs.i + 1); |
179 | si = rs.s[rs.i]; | |
180 | rs.j = (rs.j + si); | |
181 | sj = rs.s[rs.j]; | |
182 | rs.s[rs.i] = sj; | |
183 | rs.s[rs.j] = si; | |
224c7076 | 184 | |
1f2f436a | 185 | return (rs.s[(si + sj) & 0xff]); |
5b2abdfb A |
186 | } |
187 | ||
188 | static inline u_int32_t | |
1f2f436a | 189 | arc4_getword(void) |
5b2abdfb A |
190 | { |
191 | u_int32_t val; | |
224c7076 | 192 | |
1f2f436a A |
193 | val = arc4_getbyte() << 24; |
194 | val |= arc4_getbyte() << 16; | |
195 | val |= arc4_getbyte() << 8; | |
196 | val |= arc4_getbyte(); | |
224c7076 A |
197 | |
198 | return (val); | |
5b2abdfb A |
199 | } |
200 | ||
1f2f436a A |
201 | /* 7944700: force restir in child */ |
202 | __private_extern__ void | |
203 | _arc4_fork_child(void) | |
5b2abdfb | 204 | { |
1f2f436a A |
205 | rs_stired = 0; |
206 | rs_data_available = 0; | |
224c7076 A |
207 | } |
208 | ||
1f2f436a | 209 | static inline int |
224c7076 A |
210 | arc4_check_stir(void) |
211 | { | |
1f2f436a A |
212 | if (!rs_stired || arc4_count <= 0) { |
213 | arc4_stir(); | |
214 | return 1; | |
224c7076 | 215 | } |
1f2f436a | 216 | return 0; |
224c7076 A |
217 | } |
218 | ||
219 | void | |
1f2f436a | 220 | arc4random_stir(void) |
224c7076 A |
221 | { |
222 | THREAD_LOCK(); | |
1f2f436a | 223 | arc4_stir(); |
224c7076 | 224 | THREAD_UNLOCK(); |
5b2abdfb A |
225 | } |
226 | ||
227 | void | |
1f2f436a | 228 | arc4random_addrandom(u_char *dat, int datlen) |
5b2abdfb | 229 | { |
224c7076 | 230 | THREAD_LOCK(); |
224c7076 | 231 | arc4_check_stir(); |
1f2f436a | 232 | arc4_addrandom(dat, datlen); |
224c7076 | 233 | THREAD_UNLOCK(); |
5b2abdfb A |
234 | } |
235 | ||
236 | u_int32_t | |
1f2f436a | 237 | arc4random(void) |
5b2abdfb | 238 | { |
224c7076 A |
239 | u_int32_t rnd; |
240 | ||
241 | THREAD_LOCK(); | |
1f2f436a A |
242 | |
243 | int did_stir = arc4_check_stir(); | |
244 | rnd = arc4_getword(); | |
245 | arc4_count -= 4; | |
246 | ||
224c7076 | 247 | THREAD_UNLOCK(); |
1f2f436a A |
248 | if (did_stir) |
249 | { | |
250 | /* stirring used up our data pool, we need to read in new data outside of the lock */ | |
251 | arc4_fetch(); | |
252 | rs_data_available = 1; | |
253 | __sync_synchronize(); | |
254 | } | |
224c7076 A |
255 | |
256 | return (rnd); | |
5b2abdfb A |
257 | } |
258 | ||
1f2f436a A |
259 | void |
260 | arc4random_buf(void *_buf, size_t n) | |
261 | { | |
262 | u_char *buf = (u_char *)_buf; | |
263 | int did_stir = 0; | |
264 | ||
265 | THREAD_LOCK(); | |
266 | ||
267 | while (n--) { | |
268 | if (arc4_check_stir()) | |
269 | { | |
270 | did_stir = 1; | |
271 | } | |
272 | buf[n] = arc4_getbyte(); | |
273 | arc4_count--; | |
274 | } | |
275 | ||
276 | THREAD_UNLOCK(); | |
277 | if (did_stir) | |
278 | { | |
279 | /* stirring used up our data pool, we need to read in new data outside of the lock */ | |
280 | arc4_fetch(); | |
281 | rs_data_available = 1; | |
282 | __sync_synchronize(); | |
283 | } | |
284 | } | |
285 | ||
286 | /* | |
287 | * Calculate a uniformly distributed random number less than upper_bound | |
288 | * avoiding "modulo bias". | |
289 | * | |
290 | * Uniformity is achieved by generating new random numbers until the one | |
291 | * returned is outside the range [0, 2**32 % upper_bound). This | |
292 | * guarantees the selected random number will be inside | |
293 | * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound) | |
294 | * after reduction modulo upper_bound. | |
295 | */ | |
296 | u_int32_t | |
297 | arc4random_uniform(u_int32_t upper_bound) | |
298 | { | |
299 | u_int32_t r, min; | |
300 | ||
301 | if (upper_bound < 2) | |
302 | return (0); | |
303 | ||
304 | #if (ULONG_MAX > 0xffffffffUL) | |
305 | min = 0x100000000UL % upper_bound; | |
306 | #else | |
307 | /* Calculate (2**32 % upper_bound) avoiding 64-bit math */ | |
308 | if (upper_bound > 0x80000000) | |
309 | min = 1 + ~upper_bound; /* 2**32 - upper_bound */ | |
310 | else { | |
311 | /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */ | |
312 | min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound; | |
313 | } | |
314 | #endif | |
315 | ||
316 | /* | |
317 | * This could theoretically loop forever but each retry has | |
318 | * p > 0.5 (worst case, usually far better) of selecting a | |
319 | * number inside the range we need, so it should rarely need | |
320 | * to re-roll. | |
321 | */ | |
322 | for (;;) { | |
323 | r = arc4random(); | |
324 | if (r >= min) | |
325 | break; | |
326 | } | |
327 | ||
328 | return (r % upper_bound); | |
329 | } | |
330 | ||
5b2abdfb A |
331 | #if 0 |
332 | /*-------- Test code for i386 --------*/ | |
333 | #include <stdio.h> | |
334 | #include <machine/pctr.h> | |
335 | int | |
336 | main(int argc, char **argv) | |
337 | { | |
338 | const int iter = 1000000; | |
339 | int i; | |
340 | pctrval v; | |
341 | ||
342 | v = rdtsc(); | |
343 | for (i = 0; i < iter; i++) | |
344 | arc4random(); | |
345 | v = rdtsc() - v; | |
346 | v /= iter; | |
347 | ||
348 | printf("%qd cycles\n", v); | |
349 | } | |
350 | #endif |