1 /* OPENBSD ORIGINAL: lib/libc/crypto/arc4random.c */
3 /* $OpenBSD: arc4random.c,v 1.25 2013/10/01 18:34:57 markus Exp $ */
6 * Copyright (c) 1996, David Mazieres <dm@uun.org>
7 * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
8 * Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
14 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 * ChaCha based random number generator for OpenBSD.
29 #include <sys/types.h>
36 #ifndef HAVE_ARC4RANDOM
39 #include <openssl/rand.h>
40 #include <openssl/err.h>
45 #define KEYSTREAM_ONLY
46 #include "chacha_private.h"
49 #define inline __inline
52 #endif /* !__GNUC__ */
54 /* OpenSSH isn't multithreaded */
56 #define _ARC4_UNLOCK()
61 #define RSBUFSZ (16*BLOCKSZ)
62 static int rs_initialized;
63 static pid_t rs_stir_pid;
64 static chacha_ctx rs; /* chacha context for random keystream */
65 static u_char rs_buf[RSBUFSZ]; /* keystream blocks */
66 static size_t rs_have; /* valid bytes at end of rs_buf */
67 static size_t rs_count; /* bytes till reseed */
69 static inline void _rs_rekey(u_char *dat, size_t datlen);
72 _rs_init(u_char *buf, size_t n)
76 chacha_keysetup(&rs, buf, KEYSZ * 8, 0);
77 chacha_ivsetup(&rs, buf + KEYSZ);
81 #define SSH_RANDOM_DEV "/dev/urandom"
82 /* XXX use getrandom() if supported on Linux */
84 getrnd(u_char *s, size_t len)
90 if ((fd = open(SSH_RANDOM_DEV, O_RDONLY)) == -1)
91 fatal("Couldn't open %s: %s", SSH_RANDOM_DEV, strerror(errno));
93 r = read(fd, s + o, len - o);
95 if (errno == EAGAIN || errno == EINTR ||
98 fatal("read %s: %s", SSH_RANDOM_DEV, strerror(errno));
109 u_char rnd[KEYSZ + IVSZ];
112 if (RAND_bytes(rnd, sizeof(rnd)) <= 0)
113 fatal("Couldn't obtain random bytes (error %ld)",
116 getrnd(rnd, sizeof(rnd));
119 if (!rs_initialized) {
121 _rs_init(rnd, sizeof(rnd));
123 _rs_rekey(rnd, sizeof(rnd));
124 explicit_bzero(rnd, sizeof(rnd));
126 /* invalidate rs_buf */
128 memset(rs_buf, 0, RSBUFSZ);
134 _rs_stir_if_needed(size_t len)
136 pid_t pid = getpid();
138 if (rs_count <= len || !rs_initialized || rs_stir_pid != pid) {
146 _rs_rekey(u_char *dat, size_t datlen)
148 #ifndef KEYSTREAM_ONLY
149 memset(rs_buf, 0,RSBUFSZ);
151 /* fill rs_buf with the keystream */
152 chacha_encrypt_bytes(&rs, rs_buf, rs_buf, RSBUFSZ);
153 /* mix in optional user provided data */
157 m = MIN(datlen, KEYSZ + IVSZ);
158 for (i = 0; i < m; i++)
161 /* immediately reinit for backtracking resistance */
162 _rs_init(rs_buf, KEYSZ + IVSZ);
163 memset(rs_buf, 0, KEYSZ + IVSZ);
164 rs_have = RSBUFSZ - KEYSZ - IVSZ;
168 _rs_random_buf(void *_buf, size_t n)
170 u_char *buf = (u_char *)_buf;
173 _rs_stir_if_needed(n);
177 memcpy(buf, rs_buf + RSBUFSZ - rs_have, m);
178 memset(rs_buf + RSBUFSZ - rs_have, 0, m);
189 _rs_random_u32(u_int32_t *val)
191 _rs_stir_if_needed(sizeof(*val));
192 if (rs_have < sizeof(*val))
194 memcpy(val, rs_buf + RSBUFSZ - rs_have, sizeof(*val));
195 memset(rs_buf + RSBUFSZ - rs_have, 0, sizeof(*val));
196 rs_have -= sizeof(*val);
201 arc4random_stir(void)
209 arc4random_addrandom(u_char *dat, int datlen)
217 m = MIN(datlen, KEYSZ + IVSZ);
231 _rs_random_u32(&val);
237 * If we are providing arc4random, then we can provide a more efficient
240 # ifndef HAVE_ARC4RANDOM_BUF
242 arc4random_buf(void *buf, size_t n)
245 _rs_random_buf(buf, n);
248 # endif /* !HAVE_ARC4RANDOM_BUF */
249 #endif /* !HAVE_ARC4RANDOM */
251 /* arc4random_buf() that uses platform arc4random() */
252 #if !defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_ARC4RANDOM)
254 arc4random_buf(void *_buf, size_t n)
258 char *buf = (char *)_buf;
260 for (i = 0; i < n; i++) {
266 explicit_bzero(&r, sizeof(r));
268 #endif /* !defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_ARC4RANDOM) */
270 #ifndef HAVE_ARC4RANDOM_UNIFORM
272 * Calculate a uniformly distributed random number less than upper_bound
273 * avoiding "modulo bias".
275 * Uniformity is achieved by generating new random numbers until the one
276 * returned is outside the range [0, 2**32 % upper_bound). This
277 * guarantees the selected random number will be inside
278 * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
279 * after reduction modulo upper_bound.
282 arc4random_uniform(u_int32_t upper_bound)
289 /* 2**32 % x == (2**32 - x) % x */
290 min = -upper_bound % upper_bound;
293 * This could theoretically loop forever but each retry has
294 * p > 0.5 (worst case, usually far better) of selecting a
295 * number inside the range we need, so it should rarely need
304 return r % upper_bound;
306 #endif /* !HAVE_ARC4RANDOM_UNIFORM */
309 /*-------- Test code for i386 --------*/
311 #include <machine/pctr.h>
313 main(int argc, char **argv)
315 const int iter = 1000000;
320 for (i = 0; i < iter; i++)
325 printf("%qd cycles\n", v);