]>
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 | }; | |
5b2abdfb | 95 | static int rs_initialized; |
224c7076 | 96 | static int rs_stired; |
1f2f436a | 97 | static int arc4_count; |
224c7076 | 98 | |
1f2f436a A |
99 | static inline u_int8_t arc4_getbyte(void); |
100 | static void arc4_stir(void); | |
5b2abdfb | 101 | |
1f2f436a A |
102 | static struct { |
103 | struct timeval tv; | |
104 | pid_t pid; | |
105 | u_int8_t rnd[KEYSIZE]; | |
106 | } rdat; | |
107 | static volatile int rs_data_available = 0; | |
5b2abdfb A |
108 | |
109 | static inline void | |
1f2f436a | 110 | arc4_addrandom(u_char *dat, int datlen) |
5b2abdfb A |
111 | { |
112 | int n; | |
113 | u_int8_t si; | |
114 | ||
1f2f436a | 115 | rs.i--; |
5b2abdfb | 116 | for (n = 0; n < 256; n++) { |
1f2f436a A |
117 | rs.i = (rs.i + 1); |
118 | si = rs.s[rs.i]; | |
119 | rs.j = (rs.j + si + dat[n % datlen]); | |
120 | rs.s[rs.i] = rs.s[rs.j]; | |
121 | rs.s[rs.j] = si; | |
5b2abdfb | 122 | } |
1f2f436a | 123 | rs.j = rs.i; |
5b2abdfb A |
124 | } |
125 | ||
126 | static void | |
1f2f436a | 127 | arc4_fetch(void) |
5b2abdfb | 128 | { |
1f2f436a | 129 | int done, fd; |
224c7076 | 130 | fd = _open(RANDOMDEV, O_RDONLY, 0); |
1f2f436a | 131 | done = 0; |
5b2abdfb | 132 | if (fd >= 0) { |
1f2f436a A |
133 | if (_read(fd, &rdat, KEYSIZE) == KEYSIZE) |
134 | done = 1; | |
135 | (void)_close(fd); | |
224c7076 | 136 | } |
1f2f436a A |
137 | if (!done) { |
138 | (void)gettimeofday(&rdat.tv, NULL); | |
139 | rdat.pid = getpid(); | |
140 | /* We'll just take whatever was on the stack too... */ | |
141 | } | |
142 | } | |
5b2abdfb | 143 | |
1f2f436a A |
144 | static void |
145 | arc4_stir(void) | |
146 | { | |
147 | int n; | |
148 | /* | |
149 | * If we don't have data, we need some now before we can integrate | |
150 | * it into the static buffers | |
151 | */ | |
152 | if (!rs_data_available) | |
153 | { | |
154 | arc4_fetch(); | |
155 | } | |
156 | rs_data_available = 0; | |
157 | __sync_synchronize(); | |
158 | ||
159 | arc4_addrandom((u_char *)&rdat, KEYSIZE); | |
224c7076 A |
160 | |
161 | /* | |
162 | * Throw away the first N bytes of output, as suggested in the | |
163 | * paper "Weaknesses in the Key Scheduling Algorithm of RC4" | |
164 | * by Fluher, Mantin, and Shamir. N=1024 is based on | |
165 | * suggestions in the paper "(Not So) Random Shuffles of RC4" | |
166 | * by Ilya Mironov. | |
167 | */ | |
168 | for (n = 0; n < 1024; n++) | |
1f2f436a A |
169 | (void) arc4_getbyte(); |
170 | arc4_count = 1600000; | |
171 | rs_stired = 1; | |
5b2abdfb A |
172 | } |
173 | ||
174 | static inline u_int8_t | |
1f2f436a | 175 | arc4_getbyte(void) |
5b2abdfb A |
176 | { |
177 | u_int8_t si, sj; | |
178 | ||
1f2f436a A |
179 | rs.i = (rs.i + 1); |
180 | si = rs.s[rs.i]; | |
181 | rs.j = (rs.j + si); | |
182 | sj = rs.s[rs.j]; | |
183 | rs.s[rs.i] = sj; | |
184 | rs.s[rs.j] = si; | |
224c7076 | 185 | |
1f2f436a | 186 | return (rs.s[(si + sj) & 0xff]); |
5b2abdfb A |
187 | } |
188 | ||
189 | static inline u_int32_t | |
1f2f436a | 190 | arc4_getword(void) |
5b2abdfb A |
191 | { |
192 | u_int32_t val; | |
224c7076 | 193 | |
1f2f436a A |
194 | val = arc4_getbyte() << 24; |
195 | val |= arc4_getbyte() << 16; | |
196 | val |= arc4_getbyte() << 8; | |
197 | val |= arc4_getbyte(); | |
224c7076 A |
198 | |
199 | return (val); | |
5b2abdfb A |
200 | } |
201 | ||
1f2f436a A |
202 | /* 7944700: force restir in child */ |
203 | __private_extern__ void | |
204 | _arc4_fork_child(void) | |
5b2abdfb | 205 | { |
1f2f436a A |
206 | rs_stired = 0; |
207 | rs_data_available = 0; | |
224c7076 A |
208 | } |
209 | ||
1f2f436a | 210 | static inline int |
224c7076 A |
211 | arc4_check_stir(void) |
212 | { | |
1f2f436a A |
213 | if (!rs_stired || arc4_count <= 0) { |
214 | arc4_stir(); | |
215 | return 1; | |
224c7076 | 216 | } |
1f2f436a | 217 | return 0; |
224c7076 A |
218 | } |
219 | ||
220 | void | |
1f2f436a | 221 | arc4random_stir(void) |
224c7076 A |
222 | { |
223 | THREAD_LOCK(); | |
1f2f436a | 224 | arc4_stir(); |
224c7076 | 225 | THREAD_UNLOCK(); |
5b2abdfb A |
226 | } |
227 | ||
228 | void | |
1f2f436a | 229 | arc4random_addrandom(u_char *dat, int datlen) |
5b2abdfb | 230 | { |
224c7076 | 231 | THREAD_LOCK(); |
224c7076 | 232 | arc4_check_stir(); |
1f2f436a | 233 | arc4_addrandom(dat, datlen); |
224c7076 | 234 | THREAD_UNLOCK(); |
5b2abdfb A |
235 | } |
236 | ||
237 | u_int32_t | |
1f2f436a | 238 | arc4random(void) |
5b2abdfb | 239 | { |
224c7076 A |
240 | u_int32_t rnd; |
241 | ||
242 | THREAD_LOCK(); | |
1f2f436a A |
243 | |
244 | int did_stir = arc4_check_stir(); | |
245 | rnd = arc4_getword(); | |
246 | arc4_count -= 4; | |
247 | ||
224c7076 | 248 | THREAD_UNLOCK(); |
1f2f436a A |
249 | if (did_stir) |
250 | { | |
251 | /* stirring used up our data pool, we need to read in new data outside of the lock */ | |
252 | arc4_fetch(); | |
253 | rs_data_available = 1; | |
254 | __sync_synchronize(); | |
255 | } | |
224c7076 A |
256 | |
257 | return (rnd); | |
5b2abdfb A |
258 | } |
259 | ||
1f2f436a A |
260 | void |
261 | arc4random_buf(void *_buf, size_t n) | |
262 | { | |
263 | u_char *buf = (u_char *)_buf; | |
264 | int did_stir = 0; | |
265 | ||
266 | THREAD_LOCK(); | |
267 | ||
268 | while (n--) { | |
269 | if (arc4_check_stir()) | |
270 | { | |
271 | did_stir = 1; | |
272 | } | |
273 | buf[n] = arc4_getbyte(); | |
274 | arc4_count--; | |
275 | } | |
276 | ||
277 | THREAD_UNLOCK(); | |
278 | if (did_stir) | |
279 | { | |
280 | /* stirring used up our data pool, we need to read in new data outside of the lock */ | |
281 | arc4_fetch(); | |
282 | rs_data_available = 1; | |
283 | __sync_synchronize(); | |
284 | } | |
285 | } | |
286 | ||
287 | /* | |
288 | * Calculate a uniformly distributed random number less than upper_bound | |
289 | * avoiding "modulo bias". | |
290 | * | |
291 | * Uniformity is achieved by generating new random numbers until the one | |
292 | * returned is outside the range [0, 2**32 % upper_bound). This | |
293 | * guarantees the selected random number will be inside | |
294 | * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound) | |
295 | * after reduction modulo upper_bound. | |
296 | */ | |
297 | u_int32_t | |
298 | arc4random_uniform(u_int32_t upper_bound) | |
299 | { | |
300 | u_int32_t r, min; | |
301 | ||
302 | if (upper_bound < 2) | |
303 | return (0); | |
304 | ||
305 | #if (ULONG_MAX > 0xffffffffUL) | |
306 | min = 0x100000000UL % upper_bound; | |
307 | #else | |
308 | /* Calculate (2**32 % upper_bound) avoiding 64-bit math */ | |
309 | if (upper_bound > 0x80000000) | |
310 | min = 1 + ~upper_bound; /* 2**32 - upper_bound */ | |
311 | else { | |
312 | /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */ | |
313 | min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound; | |
314 | } | |
315 | #endif | |
316 | ||
317 | /* | |
318 | * This could theoretically loop forever but each retry has | |
319 | * p > 0.5 (worst case, usually far better) of selecting a | |
320 | * number inside the range we need, so it should rarely need | |
321 | * to re-roll. | |
322 | */ | |
323 | for (;;) { | |
324 | r = arc4random(); | |
325 | if (r >= min) | |
326 | break; | |
327 | } | |
328 | ||
329 | return (r % upper_bound); | |
330 | } | |
331 | ||
5b2abdfb A |
332 | #if 0 |
333 | /*-------- Test code for i386 --------*/ | |
334 | #include <stdio.h> | |
335 | #include <machine/pctr.h> | |
336 | int | |
337 | main(int argc, char **argv) | |
338 | { | |
339 | const int iter = 1000000; | |
340 | int i; | |
341 | pctrval v; | |
342 | ||
343 | v = rdtsc(); | |
344 | for (i = 0; i < iter; i++) | |
345 | arc4random(); | |
346 | v = rdtsc() - v; | |
347 | v /= iter; | |
348 | ||
349 | printf("%qd cycles\n", v); | |
350 | } | |
351 | #endif |