/src/pdns/ext/arc4random/arc4random.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* $OpenBSD: arc4random.c,v 1.58 2022/07/31 13:41:45 tb Exp $ */ |
2 | | |
3 | | /* |
4 | | * Copyright (c) 1996, David Mazieres <dm@uun.org> |
5 | | * Copyright (c) 2008, Damien Miller <djm@openbsd.org> |
6 | | * Copyright (c) 2013, Markus Friedl <markus@openbsd.org> |
7 | | * Copyright (c) 2014, Theo de Raadt <deraadt@openbsd.org> |
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 | | /* OPENBSD ORIGINAL: lib/libc/crypt/arc4random.c */ |
27 | | |
28 | | #include "includes.h" |
29 | | |
30 | | #include <sys/types.h> |
31 | | |
32 | | #include <fcntl.h> |
33 | | #include <limits.h> |
34 | | #include <signal.h> |
35 | | #ifdef HAVE_STDINT_H |
36 | | #include <stdint.h> |
37 | | #endif |
38 | | #include <stdlib.h> |
39 | | #include <string.h> |
40 | | #include <unistd.h> |
41 | | #include <sys/types.h> |
42 | | #include <sys/time.h> |
43 | | |
44 | | #ifndef HAVE_ARC4RANDOM |
45 | | |
46 | | /* |
47 | | * Always use the getentropy implementation from bsd-getentropy.c, which |
48 | | * will call a native getentropy if available then fall back as required. |
49 | | * We use a different name so that OpenSSL cannot call the wrong getentropy. |
50 | | */ |
51 | | #ifdef getentropy |
52 | | # undef getentropy |
53 | | #endif |
54 | 0 | #define getentropy(x, y) (_ssh_compat_getentropy((x), (y))) |
55 | | |
56 | | #include "log.h" |
57 | | |
58 | | #define KEYSTREAM_ONLY |
59 | | #include "chacha_private.h" |
60 | | |
61 | 0 | #define minimum(a, b) ((a) < (b) ? (a) : (b)) |
62 | | |
63 | | #if defined(__GNUC__) || defined(_MSC_VER) |
64 | | #define inline __inline |
65 | | #else /* __GNUC__ || _MSC_VER */ |
66 | | #define inline |
67 | | #endif /* !__GNUC__ && !_MSC_VER */ |
68 | | |
69 | 0 | #define KEYSZ 32 |
70 | 0 | #define IVSZ 8 |
71 | | #define BLOCKSZ 64 |
72 | | #define RSBUFSZ (16*BLOCKSZ) |
73 | | |
74 | 0 | #define REKEY_BASE (1024*1024) /* NB. should be a power of 2 */ |
75 | | |
76 | | /* Marked MAP_INHERIT_ZERO, so zero'd out in fork children. */ |
77 | | static struct _rs { |
78 | | size_t rs_have; /* valid bytes at end of rs_buf */ |
79 | | size_t rs_count; /* bytes till reseed */ |
80 | | } *rs; |
81 | | |
82 | | /* Maybe be preserved in fork children, if _rs_allocate() decides. */ |
83 | | static struct _rsx { |
84 | | chacha_ctx rs_chacha; /* chacha context for random keystream */ |
85 | | u_char rs_buf[RSBUFSZ]; /* keystream blocks */ |
86 | | } *rsx; |
87 | | |
88 | | static inline int _rs_allocate(struct _rs **, struct _rsx **); |
89 | | static inline void _rs_forkdetect(void); |
90 | | #include "arc4random.h" |
91 | | |
92 | | static inline void _rs_rekey(u_char *dat, size_t datlen); |
93 | | |
94 | | static inline void |
95 | | _rs_init(u_char *buf, size_t n) |
96 | 0 | { |
97 | 0 | if (n < KEYSZ + IVSZ) |
98 | 0 | return; |
99 | | |
100 | 0 | if (rs == NULL) { |
101 | 0 | if (_rs_allocate(&rs, &rsx) == -1) |
102 | 0 | _exit(1); |
103 | 0 | } |
104 | | |
105 | 0 | chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8); |
106 | 0 | chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ); |
107 | 0 | } |
108 | | |
109 | | static void |
110 | | _rs_stir(void) |
111 | 0 | { |
112 | 0 | u_char rnd[KEYSZ + IVSZ]; |
113 | 0 | uint32_t rekey_fuzz = 0; |
114 | |
|
115 | 0 | if (getentropy(rnd, sizeof rnd) == -1) |
116 | 0 | _getentropy_fail(); |
117 | |
|
118 | 0 | if (!rs) |
119 | 0 | _rs_init(rnd, sizeof(rnd)); |
120 | 0 | else |
121 | 0 | _rs_rekey(rnd, sizeof(rnd)); |
122 | 0 | explicit_bzero(rnd, sizeof(rnd)); /* discard source seed */ |
123 | | |
124 | | /* invalidate rs_buf */ |
125 | 0 | rs->rs_have = 0; |
126 | 0 | memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); |
127 | | |
128 | | /* rekey interval should not be predictable */ |
129 | 0 | chacha_encrypt_bytes(&rsx->rs_chacha, (uint8_t *)&rekey_fuzz, |
130 | 0 | (uint8_t *)&rekey_fuzz, sizeof(rekey_fuzz)); |
131 | 0 | rs->rs_count = REKEY_BASE + (rekey_fuzz % REKEY_BASE); |
132 | 0 | } |
133 | | |
134 | | static inline void |
135 | | _rs_stir_if_needed(size_t len) |
136 | 0 | { |
137 | 0 | _rs_forkdetect(); |
138 | 0 | if (!rs || rs->rs_count <= len) |
139 | 0 | _rs_stir(); |
140 | 0 | if (rs->rs_count <= len) |
141 | 0 | rs->rs_count = 0; |
142 | 0 | else |
143 | 0 | rs->rs_count -= len; |
144 | 0 | } |
145 | | |
146 | | static inline void |
147 | | _rs_rekey(u_char *dat, size_t datlen) |
148 | 0 | { |
149 | | #ifndef KEYSTREAM_ONLY |
150 | | memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); |
151 | | #endif |
152 | | /* fill rs_buf with the keystream */ |
153 | 0 | chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf, |
154 | 0 | rsx->rs_buf, sizeof(rsx->rs_buf)); |
155 | | /* mix in optional user provided data */ |
156 | 0 | if (dat) { |
157 | 0 | size_t i, m; |
158 | |
|
159 | 0 | m = minimum(datlen, KEYSZ + IVSZ); |
160 | 0 | for (i = 0; i < m; i++) |
161 | 0 | rsx->rs_buf[i] ^= dat[i]; |
162 | 0 | } |
163 | | /* immediately reinit for backtracking resistance */ |
164 | 0 | _rs_init(rsx->rs_buf, KEYSZ + IVSZ); |
165 | 0 | memset(rsx->rs_buf, 0, KEYSZ + IVSZ); |
166 | 0 | rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ; |
167 | 0 | } |
168 | | |
169 | | static inline void |
170 | | _rs_random_buf(void *_buf, size_t n) |
171 | 0 | { |
172 | 0 | u_char *buf = (u_char *)_buf; |
173 | 0 | u_char *keystream; |
174 | 0 | size_t m; |
175 | |
|
176 | 0 | _rs_stir_if_needed(n); |
177 | 0 | while (n > 0) { |
178 | 0 | if (rs->rs_have > 0) { |
179 | 0 | m = minimum(n, rs->rs_have); |
180 | 0 | keystream = rsx->rs_buf + sizeof(rsx->rs_buf) |
181 | 0 | - rs->rs_have; |
182 | 0 | memcpy(buf, keystream, m); |
183 | 0 | memset(keystream, 0, m); |
184 | 0 | buf += m; |
185 | 0 | n -= m; |
186 | 0 | rs->rs_have -= m; |
187 | 0 | } |
188 | 0 | if (rs->rs_have == 0) |
189 | 0 | _rs_rekey(NULL, 0); |
190 | 0 | } |
191 | 0 | } |
192 | | |
193 | | static inline void |
194 | | _rs_random_u32(uint32_t *val) |
195 | 0 | { |
196 | 0 | u_char *keystream; |
197 | |
|
198 | 0 | _rs_stir_if_needed(sizeof(*val)); |
199 | 0 | if (rs->rs_have < sizeof(*val)) |
200 | 0 | _rs_rekey(NULL, 0); |
201 | 0 | keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have; |
202 | 0 | memcpy(val, keystream, sizeof(*val)); |
203 | 0 | memset(keystream, 0, sizeof(*val)); |
204 | 0 | rs->rs_have -= sizeof(*val); |
205 | 0 | } |
206 | | |
207 | | #include <pthread.h> |
208 | | static pthread_mutex_t arc4mutex = PTHREAD_MUTEX_INITIALIZER; |
209 | | |
210 | | uint32_t |
211 | | arc4random(void) |
212 | 0 | { |
213 | 0 | uint32_t val; |
214 | |
|
215 | 0 | _ARC4_LOCK(); |
216 | 0 | _rs_random_u32(&val); |
217 | 0 | _ARC4_UNLOCK(); |
218 | 0 | return val; |
219 | 0 | } |
220 | | DEF_WEAK(arc4random); |
221 | | |
222 | | /* |
223 | | * If we are providing arc4random, then we can provide a more efficient |
224 | | * arc4random_buf(). |
225 | | */ |
226 | | # ifndef HAVE_ARC4RANDOM_BUF |
227 | | void |
228 | | arc4random_buf(void *buf, size_t n) |
229 | 0 | { |
230 | 0 | _ARC4_LOCK(); |
231 | 0 | _rs_random_buf(buf, n); |
232 | 0 | _ARC4_UNLOCK(); |
233 | 0 | } |
234 | | DEF_WEAK(arc4random_buf); |
235 | | # endif /* !HAVE_ARC4RANDOM_BUF */ |
236 | | #endif /* !HAVE_ARC4RANDOM */ |
237 | | |
238 | | /* arc4random_buf() that uses platform arc4random() */ |
239 | | #if !defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_ARC4RANDOM) |
240 | | void |
241 | | arc4random_buf(void *_buf, size_t n) |
242 | | { |
243 | | size_t i; |
244 | | u_int32_t r = 0; |
245 | | char *buf = (char *)_buf; |
246 | | |
247 | | for (i = 0; i < n; i++) { |
248 | | if (i % 4 == 0) |
249 | | r = arc4random(); |
250 | | buf[i] = r & 0xff; |
251 | | r >>= 8; |
252 | | } |
253 | | explicit_bzero(&r, sizeof(r)); |
254 | | } |
255 | | #endif /* !defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_ARC4RANDOM) */ |
256 | | |