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 #ifdef HAVE_SYS_RANDOM_H
37 # include <sys/random.h>
40 #ifndef HAVE_ARC4RANDOM
43 #include <openssl/rand.h>
44 #include <openssl/err.h>
49 #define KEYSTREAM_ONLY
50 #include "chacha_private.h"
53 #define inline __inline
56 #endif /* !__GNUC__ */
58 /* OpenSSH isn't multithreaded */
60 #define _ARC4_UNLOCK()
65 #define RSBUFSZ (16*BLOCKSZ)
66 static int rs_initialized;
67 static pid_t rs_stir_pid;
68 static chacha_ctx rs; /* chacha context for random keystream */
69 static u_char rs_buf[RSBUFSZ]; /* keystream blocks */
70 static size_t rs_have; /* valid bytes at end of rs_buf */
71 static size_t rs_count; /* bytes till reseed */
73 static inline void _rs_rekey(u_char *dat, size_t datlen);
76 _rs_init(u_char *buf, size_t n)
80 chacha_keysetup(&rs, buf, KEYSZ * 8, 0);
81 chacha_ivsetup(&rs, buf + KEYSZ);
85 # ifndef SSH_RANDOM_DEV
86 # define SSH_RANDOM_DEV "/dev/urandom"
87 # endif /* SSH_RANDOM_DEV */
89 getrnd(u_char *s, size_t len)
96 if ((r = getrandom(s, len, 0)) > 0 && (size_t)r == len)
98 #endif /* HAVE_GETRANDOM */
100 if ((fd = open(SSH_RANDOM_DEV, O_RDONLY)) == -1)
101 fatal("Couldn't open %s: %s", SSH_RANDOM_DEV, strerror(errno));
103 r = read(fd, s + o, len - o);
105 if (errno == EAGAIN || errno == EINTR ||
106 errno == EWOULDBLOCK)
108 fatal("read %s: %s", SSH_RANDOM_DEV, strerror(errno));
114 #endif /* WITH_OPENSSL */
119 u_char rnd[KEYSZ + IVSZ];
122 if (RAND_bytes(rnd, sizeof(rnd)) <= 0)
123 fatal("Couldn't obtain random bytes (error 0x%lx)",
124 (unsigned long)ERR_get_error());
126 getrnd(rnd, sizeof(rnd));
129 if (!rs_initialized) {
131 _rs_init(rnd, sizeof(rnd));
133 _rs_rekey(rnd, sizeof(rnd));
134 explicit_bzero(rnd, sizeof(rnd));
136 /* invalidate rs_buf */
138 memset(rs_buf, 0, RSBUFSZ);
144 _rs_stir_if_needed(size_t len)
146 pid_t pid = getpid();
148 if (rs_count <= len || !rs_initialized || rs_stir_pid != pid) {
156 _rs_rekey(u_char *dat, size_t datlen)
158 #ifndef KEYSTREAM_ONLY
159 memset(rs_buf, 0,RSBUFSZ);
161 /* fill rs_buf with the keystream */
162 chacha_encrypt_bytes(&rs, rs_buf, rs_buf, RSBUFSZ);
163 /* mix in optional user provided data */
167 m = MIN(datlen, KEYSZ + IVSZ);
168 for (i = 0; i < m; i++)
171 /* immediately reinit for backtracking resistance */
172 _rs_init(rs_buf, KEYSZ + IVSZ);
173 memset(rs_buf, 0, KEYSZ + IVSZ);
174 rs_have = RSBUFSZ - KEYSZ - IVSZ;
178 _rs_random_buf(void *_buf, size_t n)
180 u_char *buf = (u_char *)_buf;
183 _rs_stir_if_needed(n);
187 memcpy(buf, rs_buf + RSBUFSZ - rs_have, m);
188 memset(rs_buf + RSBUFSZ - rs_have, 0, m);
199 _rs_random_u32(u_int32_t *val)
201 _rs_stir_if_needed(sizeof(*val));
202 if (rs_have < sizeof(*val))
204 memcpy(val, rs_buf + RSBUFSZ - rs_have, sizeof(*val));
205 memset(rs_buf + RSBUFSZ - rs_have, 0, sizeof(*val));
206 rs_have -= sizeof(*val);
211 arc4random_stir(void)
219 arc4random_addrandom(u_char *dat, int datlen)
227 m = MIN(datlen, KEYSZ + IVSZ);
241 _rs_random_u32(&val);
247 * If we are providing arc4random, then we can provide a more efficient
250 # ifndef HAVE_ARC4RANDOM_BUF
252 arc4random_buf(void *buf, size_t n)
255 _rs_random_buf(buf, n);
258 # endif /* !HAVE_ARC4RANDOM_BUF */
259 #endif /* !HAVE_ARC4RANDOM */
261 /* arc4random_buf() that uses platform arc4random() */
262 #if !defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_ARC4RANDOM)
264 arc4random_buf(void *_buf, size_t n)
268 char *buf = (char *)_buf;
270 for (i = 0; i < n; i++) {
276 explicit_bzero(&r, sizeof(r));
278 #endif /* !defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_ARC4RANDOM) */
280 #ifndef HAVE_ARC4RANDOM_UNIFORM
282 * Calculate a uniformly distributed random number less than upper_bound
283 * avoiding "modulo bias".
285 * Uniformity is achieved by generating new random numbers until the one
286 * returned is outside the range [0, 2**32 % upper_bound). This
287 * guarantees the selected random number will be inside
288 * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
289 * after reduction modulo upper_bound.
292 arc4random_uniform(u_int32_t upper_bound)
299 /* 2**32 % x == (2**32 - x) % x */
300 min = -upper_bound % upper_bound;
303 * This could theoretically loop forever but each retry has
304 * p > 0.5 (worst case, usually far better) of selecting a
305 * number inside the range we need, so it should rarely need
314 return r % upper_bound;
316 #endif /* !HAVE_ARC4RANDOM_UNIFORM */
319 /*-------- Test code for i386 --------*/
321 #include <machine/pctr.h>
323 main(int argc, char **argv)
325 const int iter = 1000000;
330 for (i = 0; i < iter; i++)
335 printf("%qd cycles\n", v);