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 #include <sys/cdefs.h> 27 __FBSDID("$FreeBSD$"); 28 29 #include "namespace.h" 30 #if defined(__FreeBSD__) 31 #include <assert.h> 32 #endif 33 #include <fcntl.h> 34 #include <limits.h> 35 #include <pthread.h> 36 #include <signal.h> 37 #include <stdint.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <unistd.h> 41 #include <sys/types.h> 42 #include <sys/time.h> 43 44 #include "libc_private.h" 45 #include "un-namespace.h" 46 47 #define CHACHA_EMBED 48 #define KEYSTREAM_ONLY 49 #if defined(__FreeBSD__) 50 #define ARC4RANDOM_FXRNG 1 51 #else 52 #define ARC4RANDOM_FXRNG 0 53 #endif 54 #include "chacha.c" 55 56 #define minimum(a, b) ((a) < (b) ? (a) : (b)) 57 58 #if defined(__GNUC__) || defined(_MSC_VER) 59 #define inline __inline 60 #else /* __GNUC__ || _MSC_VER */ 61 #define inline 62 #endif /* !__GNUC__ && !_MSC_VER */ 63 64 #define KEYSZ 32 65 #define IVSZ 8 66 #define BLOCKSZ 64 67 #define RSBUFSZ (16*BLOCKSZ) 68 69 #define REKEY_BASE (1024*1024) /* NB. should be a power of 2 */ 70 71 /* Marked INHERIT_ZERO, so zero'd out in fork children. */ 72 static struct _rs { 73 size_t rs_have; /* valid bytes at end of rs_buf */ 74 size_t rs_count; /* bytes till reseed */ 75 } *rs; 76 77 /* Maybe be preserved in fork children, if _rs_allocate() decides. */ 78 static struct _rsx { 79 chacha_ctx rs_chacha; /* chacha context for random keystream */ 80 u_char rs_buf[RSBUFSZ]; /* keystream blocks */ 81 #ifdef __FreeBSD__ 82 uint32_t rs_seed_generation; /* 32-bit userspace RNG version */ 83 #endif 84 } *rsx; 85 86 static inline int _rs_allocate(struct _rs **, struct _rsx **); 87 static inline void _rs_forkdetect(void); 88 #include "arc4random.h" 89 90 static inline void _rs_rekey(u_char *dat, size_t datlen); 91 92 static inline void 93 _rs_init(u_char *buf, size_t n) 94 { 95 if (n < KEYSZ + IVSZ) 96 return; 97 98 if (rs == NULL) { 99 if (_rs_allocate(&rs, &rsx) == -1) 100 _exit(1); 101 } 102 103 chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8); 104 chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ, NULL); 105 } 106 107 static void 108 _rs_stir(void) 109 { 110 u_char rnd[KEYSZ + IVSZ]; 111 uint32_t rekey_fuzz = 0; 112 113 #if defined(__FreeBSD__) 114 bool need_init; 115 116 /* 117 * De-couple allocation (which locates the vdso_fxrngp pointer in 118 * auxinfo) from initialization. This allows us to read the root seed 119 * version before we fetch system entropy, maintaining the invariant 120 * that the PRF was seeded with entropy from rs_seed_generation or a 121 * later generation. But never seeded from an earlier generation. 122 * This invariant prevents us from missing a root reseed event. 123 */ 124 need_init = false; 125 if (rs == NULL) { 126 if (_rs_allocate(&rs, &rsx) == -1) 127 abort(); 128 need_init = true; 129 } 130 /* 131 * Transition period: new userspace on old kernel. This should become 132 * a hard error at some point, if the scheme is adopted. 133 */ 134 if (vdso_fxrngp != NULL) 135 rsx->rs_seed_generation = 136 fxrng_load_acq_generation(&vdso_fxrngp->fx_generation32); 137 #endif 138 139 if (getentropy(rnd, sizeof rnd) == -1) 140 _getentropy_fail(); 141 142 #if !defined(__FreeBSD__) 143 if (!rs) 144 _rs_init(rnd, sizeof(rnd)); 145 #else /* __FreeBSD__ */ 146 assert(rs != NULL); 147 if (need_init) 148 _rs_init(rnd, sizeof(rnd)); 149 #endif 150 else 151 _rs_rekey(rnd, sizeof(rnd)); 152 explicit_bzero(rnd, sizeof(rnd)); /* discard source seed */ 153 154 /* invalidate rs_buf */ 155 rs->rs_have = 0; 156 memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); 157 158 /* rekey interval should not be predictable */ 159 chacha_encrypt_bytes(&rsx->rs_chacha, (uint8_t *)&rekey_fuzz, 160 (uint8_t *)&rekey_fuzz, sizeof(rekey_fuzz)); 161 rs->rs_count = REKEY_BASE + (rekey_fuzz % REKEY_BASE); 162 } 163 164 static inline void 165 _rs_stir_if_needed(size_t len) 166 { 167 _rs_forkdetect(); 168 if (!rs || rs->rs_count <= len) 169 _rs_stir(); 170 if (rs->rs_count <= len) 171 rs->rs_count = 0; 172 else 173 rs->rs_count -= len; 174 } 175 176 static inline void 177 _rs_rekey(u_char *dat, size_t datlen) 178 { 179 #ifndef KEYSTREAM_ONLY 180 memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); 181 #endif 182 /* fill rs_buf with the keystream */ 183 chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf, 184 rsx->rs_buf, sizeof(rsx->rs_buf)); 185 /* mix in optional user provided data */ 186 if (dat) { 187 size_t i, m; 188 189 m = minimum(datlen, KEYSZ + IVSZ); 190 for (i = 0; i < m; i++) 191 rsx->rs_buf[i] ^= dat[i]; 192 } 193 /* immediately reinit for backtracking resistance */ 194 _rs_init(rsx->rs_buf, KEYSZ + IVSZ); 195 memset(rsx->rs_buf, 0, KEYSZ + IVSZ); 196 rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ; 197 } 198 199 static inline void 200 _rs_random_buf(void *_buf, size_t n) 201 { 202 u_char *buf = (u_char *)_buf; 203 u_char *keystream; 204 size_t m; 205 206 _rs_stir_if_needed(n); 207 while (n > 0) { 208 if (rs->rs_have > 0) { 209 m = minimum(n, rs->rs_have); 210 keystream = rsx->rs_buf + sizeof(rsx->rs_buf) 211 - rs->rs_have; 212 memcpy(buf, keystream, m); 213 memset(keystream, 0, m); 214 buf += m; 215 n -= m; 216 rs->rs_have -= m; 217 } 218 if (rs->rs_have == 0) 219 _rs_rekey(NULL, 0); 220 } 221 } 222 223 static inline void 224 _rs_random_u32(uint32_t *val) 225 { 226 u_char *keystream; 227 228 _rs_stir_if_needed(sizeof(*val)); 229 if (rs->rs_have < sizeof(*val)) 230 _rs_rekey(NULL, 0); 231 keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have; 232 memcpy(val, keystream, sizeof(*val)); 233 memset(keystream, 0, sizeof(*val)); 234 rs->rs_have -= sizeof(*val); 235 } 236 237 uint32_t 238 arc4random(void) 239 { 240 uint32_t val; 241 242 _ARC4_LOCK(); 243 _rs_random_u32(&val); 244 _ARC4_UNLOCK(); 245 return val; 246 } 247 248 void 249 arc4random_buf(void *buf, size_t n) 250 { 251 _ARC4_LOCK(); 252 _rs_random_buf(buf, n); 253 _ARC4_UNLOCK(); 254 } 255