]> git.saurik.com Git - apple/libc.git/blame - gen/FreeBSD/arc4random.c
Libc-1353.11.2.tar.gz
[apple/libc.git] / gen / FreeBSD / arc4random.c
CommitLineData
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 37
224c7076
A
38#include <sys/types.h>
39#include <sys/time.h>
974e3884
A
40#include <sys/param.h>
41#include <sys/random.h>
5b2abdfb
A
42#include <fcntl.h>
43#include <unistd.h>
224c7076 44#include <pthread.h>
507116e3
A
45
46#include <TargetConditionals.h>
47#if !TARGET_OS_DRIVERKIT
48#define OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE 1
49#endif
974e3884
A
50#include <os/assumes.h>
51#include <os/lock.h>
224c7076 52
974e3884 53#include "string.h"
224c7076 54#include "libc_private.h"
974e3884 55
507116e3
A
56#if defined(__APPLE__) && !defined(VARIANT_STATIC)
57#include <corecrypto/ccrng.h>
974e3884 58
507116e3 59static struct ccrng_state *rng;
974e3884 60
507116e3
A
61static void
62arc4_init(void)
63{
64 int err;
65
66 if (rng != NULL) return;
67
68 rng = ccrng(&err);
69 if (rng == NULL) {
70#if OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE
71 os_crash("arc4random: unable to get ccrng() handle (%d)", err);
72#else
73 os_crash("arc4random: unable to get ccrng() handle");
74#endif
75 }
76}
77
78void
79arc4random_addrandom(__unused u_char *dat, __unused int datlen)
80{
81 /* NOP - deprecated */
82}
83
84uint32_t
85arc4random(void)
86{
87 uint32_t rand;
974e3884 88
507116e3
A
89 arc4random_buf(&rand, sizeof(rand));
90
91 return rand;
92}
93
94void
95arc4random_buf(void *buf, size_t buf_size)
96{
97 arc4_init();
98 ccrng_generate(rng, buf_size, buf);
99}
100
101void
102arc4random_stir(void)
103{
104 /* NOP */
105}
106
107uint32_t
108arc4random_uniform(uint32_t upper_bound)
109{
110 uint64_t rand;
111
112 arc4_init();
113 ccrng_uniform(rng, upper_bound, &rand);
114
115 return (uint32_t)rand;
116}
117
118__private_extern__ void
119_arc4_fork_child(void)
120{
121 /* NOP */
122}
123
124#else /* __APPLE__ && !VARIANT_STATIC */
974e3884
A
125
126#define RANDOMDEV "/dev/random"
127
128static void
129_my_getentropy(uint8_t *buf, size_t size){
130 int fd;
131 ssize_t ret;
132 if (getentropy(buf, size) == 0) {
133 return;
134 }
135
136 // The above should never fail, but we'll try /dev/random anyway
137 fd = open(RANDOMDEV, O_RDONLY, 0);
138 if (fd == -1) {
139#if !defined(VARIANT_STATIC)
140 os_crash("arc4random: unable to open /dev/random");
141#else
142 abort();
143#endif
144 }
145shortread:
146 ret = read(fd, buf, size);
147 if (ret == -1) {
148#if !defined(VARIANT_STATIC)
149 os_crash("arc4random: unable to read from /dev/random");
150#else
151 abort();
152#endif
153 } else if ((size_t)ret < size) {
154 size -= (size_t)ret;
155 buf += ret;
156 goto shortread;
157 }
158 (void)close(fd);
159}
160
5b2abdfb
A
161struct arc4_stream {
162 u_int8_t i;
163 u_int8_t j;
164 u_int8_t s[256];
165};
166
1f2f436a 167#define KEYSIZE 128
224c7076 168
1f2f436a
A
169static struct arc4_stream rs = {
170 .i = 0,
171 .j = 0,
172 .s = {
173 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
174 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
175 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
176 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
177 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
178 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
179 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
180 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
181 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
182 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
183 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
184 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
185 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
186 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
187 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
188 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
189 }
190};
224c7076
A
191static int rs_stired;
192
1f2f436a
A
193static inline u_int8_t arc4_getbyte(void);
194static void arc4_stir(void);
5b2abdfb 195
1f2f436a
A
196static struct {
197 struct timeval tv;
198 pid_t pid;
199 u_int8_t rnd[KEYSIZE];
200} rdat;
201static volatile int rs_data_available = 0;
5b2abdfb
A
202
203static inline void
1f2f436a 204arc4_addrandom(u_char *dat, int datlen)
5b2abdfb
A
205{
206 int n;
207 u_int8_t si;
208
1f2f436a 209 rs.i--;
5b2abdfb 210 for (n = 0; n < 256; n++) {
1f2f436a
A
211 rs.i = (rs.i + 1);
212 si = rs.s[rs.i];
213 rs.j = (rs.j + si + dat[n % datlen]);
214 rs.s[rs.i] = rs.s[rs.j];
215 rs.s[rs.j] = si;
5b2abdfb 216 }
1f2f436a 217 rs.j = rs.i;
5b2abdfb
A
218}
219
220static void
1f2f436a 221arc4_fetch(void)
5b2abdfb 222{
974e3884 223 _my_getentropy((uint8_t*)&rdat, KEYSIZE);
1f2f436a 224}
5b2abdfb 225
507116e3
A
226static os_unfair_lock arc4_lock = OS_UNFAIR_LOCK_INIT;
227static int arc4_count;
228
1f2f436a
A
229static void
230arc4_stir(void)
231{
232 int n;
233 /*
234 * If we don't have data, we need some now before we can integrate
235 * it into the static buffers
236 */
237 if (!rs_data_available)
238 {
239 arc4_fetch();
240 }
241 rs_data_available = 0;
242 __sync_synchronize();
243
244 arc4_addrandom((u_char *)&rdat, KEYSIZE);
224c7076
A
245
246 /*
247 * Throw away the first N bytes of output, as suggested in the
248 * paper "Weaknesses in the Key Scheduling Algorithm of RC4"
249 * by Fluher, Mantin, and Shamir. N=1024 is based on
250 * suggestions in the paper "(Not So) Random Shuffles of RC4"
251 * by Ilya Mironov.
252 */
253 for (n = 0; n < 1024; n++)
1f2f436a
A
254 (void) arc4_getbyte();
255 arc4_count = 1600000;
256 rs_stired = 1;
5b2abdfb
A
257}
258
259static inline u_int8_t
1f2f436a 260arc4_getbyte(void)
5b2abdfb
A
261{
262 u_int8_t si, sj;
263
1f2f436a
A
264 rs.i = (rs.i + 1);
265 si = rs.s[rs.i];
266 rs.j = (rs.j + si);
267 sj = rs.s[rs.j];
268 rs.s[rs.i] = sj;
269 rs.s[rs.j] = si;
224c7076 270
1f2f436a 271 return (rs.s[(si + sj) & 0xff]);
5b2abdfb
A
272}
273
274static inline u_int32_t
1f2f436a 275arc4_getword(void)
5b2abdfb
A
276{
277 u_int32_t val;
224c7076 278
1f2f436a
A
279 val = arc4_getbyte() << 24;
280 val |= arc4_getbyte() << 16;
281 val |= arc4_getbyte() << 8;
282 val |= arc4_getbyte();
224c7076
A
283
284 return (val);
5b2abdfb
A
285}
286
1f2f436a
A
287/* 7944700: force restir in child */
288__private_extern__ void
289_arc4_fork_child(void)
5b2abdfb 290{
974e3884 291 arc4_lock = OS_UNFAIR_LOCK_INIT;
1f2f436a
A
292 rs_stired = 0;
293 rs_data_available = 0;
224c7076
A
294}
295
1f2f436a 296static inline int
224c7076
A
297arc4_check_stir(void)
298{
1f2f436a
A
299 if (!rs_stired || arc4_count <= 0) {
300 arc4_stir();
301 return 1;
224c7076 302 }
1f2f436a 303 return 0;
224c7076
A
304}
305
5b2abdfb 306void
1f2f436a 307arc4random_addrandom(u_char *dat, int datlen)
5b2abdfb 308{
974e3884 309 os_unfair_lock_lock(&arc4_lock);
224c7076 310 arc4_check_stir();
1f2f436a 311 arc4_addrandom(dat, datlen);
974e3884 312 os_unfair_lock_unlock(&arc4_lock);
5b2abdfb
A
313}
314
315u_int32_t
1f2f436a 316arc4random(void)
5b2abdfb 317{
224c7076
A
318 u_int32_t rnd;
319
974e3884 320 os_unfair_lock_lock(&arc4_lock);
1f2f436a
A
321
322 int did_stir = arc4_check_stir();
323 rnd = arc4_getword();
324 arc4_count -= 4;
325
974e3884 326 os_unfair_lock_unlock(&arc4_lock);
1f2f436a
A
327 if (did_stir)
328 {
329 /* stirring used up our data pool, we need to read in new data outside of the lock */
330 arc4_fetch();
331 rs_data_available = 1;
332 __sync_synchronize();
333 }
224c7076
A
334
335 return (rnd);
5b2abdfb
A
336}
337
1f2f436a
A
338void
339arc4random_buf(void *_buf, size_t n)
340{
341 u_char *buf = (u_char *)_buf;
342 int did_stir = 0;
343
974e3884 344 os_unfair_lock_lock(&arc4_lock);
1f2f436a
A
345
346 while (n--) {
347 if (arc4_check_stir())
348 {
349 did_stir = 1;
350 }
351 buf[n] = arc4_getbyte();
352 arc4_count--;
353 }
974e3884
A
354
355 os_unfair_lock_unlock(&arc4_lock);
1f2f436a
A
356 if (did_stir)
357 {
358 /* stirring used up our data pool, we need to read in new data outside of the lock */
359 arc4_fetch();
360 rs_data_available = 1;
361 __sync_synchronize();
362 }
363}
364
974e3884
A
365void
366arc4random_stir(void)
367{
368 os_unfair_lock_lock(&arc4_lock);
369 arc4_stir();
370 os_unfair_lock_unlock(&arc4_lock);
371}
372
1f2f436a
A
373/*
374 * Calculate a uniformly distributed random number less than upper_bound
375 * avoiding "modulo bias".
376 *
974e3884
A
377 * Uniformity is achieved by trying successive ranges of bits from the random
378 * value, each large enough to hold the desired upper bound, until a range
379 * holding a value less than the bound is found.
1f2f436a 380 */
974e3884
A
381uint32_t
382arc4random_uniform(uint32_t upper_bound)
1f2f436a 383{
1f2f436a 384 if (upper_bound < 2)
974e3884 385 return 0;
1f2f436a 386
974e3884
A
387 // find smallest 2**n -1 >= upper_bound
388 int zeros = __builtin_clz(upper_bound);
389 int bits = CHAR_BIT * sizeof(uint32_t) - zeros;
390 uint32_t mask = 0xFFFFFFFFU >> zeros;
1f2f436a 391
974e3884
A
392 do {
393 uint32_t value = arc4random();
5b2abdfb 394
974e3884
A
395 // If low 2**n-1 bits satisfy the requested condition, return result
396 uint32_t result = value & mask;
397 if (result < upper_bound) {
398 return result;
399 }
5b2abdfb 400
974e3884
A
401 // otherwise consume remaining bits of randomness looking for a satisfactory result.
402 int bits_left = zeros;
403 while (bits_left >= bits) {
404 value >>= bits;
405 result = value & mask;
406 if (result < upper_bound) {
407 return result;
408 }
409 bits_left -= bits;
410 }
411 } while (1);
5b2abdfb 412}
507116e3
A
413
414#endif /* __APPLE__ */