1 /* $OpenBSD: arc4random.c,v 1.54 2015/09/13 08:31:47 guenther Exp $ */
2
3 /*
4 * Copyright (c) 1996, David Mazieres <[email protected]>
5 * Copyright (c) 2008, Damien Miller <[email protected]>
6 * Copyright (c) 2013, Markus Friedl <[email protected]>
7 * Copyright (c) 2014, Theo de Raadt <[email protected]>
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21
22 /*
23 * ChaCha based random number generator for OpenBSD.
24 */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include "namespace.h"
30 #include <fcntl.h>
31 #include <limits.h>
32 #include <pthread.h>
33 #include <signal.h>
34 #include <stdint.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/time.h>
40
41 #include "libc_private.h"
42 #include "un-namespace.h"
43
44 #define KEYSTREAM_ONLY
45 #include "chacha.c"
46
47 #define minimum(a, b) ((a) < (b) ? (a) : (b))
48
49 #if defined(__GNUC__) || defined(_MSC_VER)
50 #define inline __inline
51 #else /* __GNUC__ || _MSC_VER */
52 #define inline
53 #endif /* !__GNUC__ && !_MSC_VER */
54
55 #define KEYSZ 32
56 #define IVSZ 8
57 #define BLOCKSZ 64
58 #define RSBUFSZ (16*BLOCKSZ)
59
60 /* Marked INHERIT_ZERO, so zero'd out in fork children. */
61 static struct _rs {
62 size_t rs_have; /* valid bytes at end of rs_buf */
63 size_t rs_count; /* bytes till reseed */
64 } *rs;
65
66 /* Maybe be preserved in fork children, if _rs_allocate() decides. */
67 static struct _rsx {
68 chacha_ctx rs_chacha; /* chacha context for random keystream */
69 u_char rs_buf[RSBUFSZ]; /* keystream blocks */
70 } *rsx;
71
72 static inline int _rs_allocate(struct _rs **, struct _rsx **);
73 static inline void _rs_forkdetect(void);
74 #include "arc4random.h"
75
76 static inline void _rs_rekey(u_char *dat, size_t datlen);
77
78 static inline void
_rs_init(u_char * buf,size_t n)79 _rs_init(u_char *buf, size_t n)
80 {
81 if (n < KEYSZ + IVSZ)
82 return;
83
84 if (rs == NULL) {
85 if (_rs_allocate(&rs, &rsx) == -1)
86 abort();
87 }
88
89 chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8);
90 chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ, NULL);
91 }
92
93 static void
_rs_stir(void)94 _rs_stir(void)
95 {
96 u_char rnd[KEYSZ + IVSZ];
97
98 if (getentropy(rnd, sizeof rnd) == -1)
99 _getentropy_fail();
100
101 if (!rs)
102 _rs_init(rnd, sizeof(rnd));
103 else
104 _rs_rekey(rnd, sizeof(rnd));
105 explicit_bzero(rnd, sizeof(rnd)); /* discard source seed */
106
107 /* invalidate rs_buf */
108 rs->rs_have = 0;
109 memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
110
111 rs->rs_count = 1600000;
112 }
113
114 static inline void
_rs_stir_if_needed(size_t len)115 _rs_stir_if_needed(size_t len)
116 {
117 _rs_forkdetect();
118 if (!rs || rs->rs_count <= len)
119 _rs_stir();
120 if (rs->rs_count <= len)
121 rs->rs_count = 0;
122 else
123 rs->rs_count -= len;
124 }
125
126 static inline void
_rs_rekey(u_char * dat,size_t datlen)127 _rs_rekey(u_char *dat, size_t datlen)
128 {
129 #ifndef KEYSTREAM_ONLY
130 memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
131 #endif
132 /* fill rs_buf with the keystream */
133 chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf,
134 rsx->rs_buf, sizeof(rsx->rs_buf));
135 /* mix in optional user provided data */
136 if (dat) {
137 size_t i, m;
138
139 m = minimum(datlen, KEYSZ + IVSZ);
140 for (i = 0; i < m; i++)
141 rsx->rs_buf[i] ^= dat[i];
142 }
143 /* immediately reinit for backtracking resistance */
144 _rs_init(rsx->rs_buf, KEYSZ + IVSZ);
145 memset(rsx->rs_buf, 0, KEYSZ + IVSZ);
146 rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ;
147 }
148
149 static inline void
_rs_random_buf(void * _buf,size_t n)150 _rs_random_buf(void *_buf, size_t n)
151 {
152 u_char *buf = (u_char *)_buf;
153 u_char *keystream;
154 size_t m;
155
156 _rs_stir_if_needed(n);
157 while (n > 0) {
158 if (rs->rs_have > 0) {
159 m = minimum(n, rs->rs_have);
160 keystream = rsx->rs_buf + sizeof(rsx->rs_buf)
161 - rs->rs_have;
162 memcpy(buf, keystream, m);
163 memset(keystream, 0, m);
164 buf += m;
165 n -= m;
166 rs->rs_have -= m;
167 }
168 if (rs->rs_have == 0)
169 _rs_rekey(NULL, 0);
170 }
171 }
172
173 static inline void
_rs_random_u32(uint32_t * val)174 _rs_random_u32(uint32_t *val)
175 {
176 u_char *keystream;
177
178 _rs_stir_if_needed(sizeof(*val));
179 if (rs->rs_have < sizeof(*val))
180 _rs_rekey(NULL, 0);
181 keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have;
182 memcpy(val, keystream, sizeof(*val));
183 memset(keystream, 0, sizeof(*val));
184 rs->rs_have -= sizeof(*val);
185 }
186
187 uint32_t
arc4random(void)188 arc4random(void)
189 {
190 uint32_t val;
191
192 _ARC4_LOCK();
193 _rs_random_u32(&val);
194 _ARC4_UNLOCK();
195 return val;
196 }
197
198 void
arc4random_buf(void * buf,size_t n)199 arc4random_buf(void *buf, size_t n)
200 {
201 _ARC4_LOCK();
202 _rs_random_buf(buf, n);
203 _ARC4_UNLOCK();
204 }
205