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 * If we're not using a native getentropy, use the one from bsd-getentropy.c 48 * under a different name, so that if in future these binaries are run on 49 * a system that has a native getentropy OpenSSL cannot call the wrong one. 50 */ 51 #ifndef HAVE_GETENTROPY 52 # define getentropy(x, y) (_ssh_compat_getentropy((x), (y))) 53 #endif 54 55 #include "log.h" 56 57 #define KEYSTREAM_ONLY 58 #include "chacha_private.h" 59 60 #define minimum(a, b) ((a) < (b) ? (a) : (b)) 61 62 #if defined(__GNUC__) || defined(_MSC_VER) 63 #define inline __inline 64 #else /* __GNUC__ || _MSC_VER */ 65 #define inline 66 #endif /* !__GNUC__ && !_MSC_VER */ 67 68 #define KEYSZ 32 69 #define IVSZ 8 70 #define BLOCKSZ 64 71 #define RSBUFSZ (16*BLOCKSZ) 72 73 #define REKEY_BASE (1024*1024) /* NB. should be a power of 2 */ 74 75 /* Marked MAP_INHERIT_ZERO, so zero'd out in fork children. */ 76 static struct _rs { 77 size_t rs_have; /* valid bytes at end of rs_buf */ 78 size_t rs_count; /* bytes till reseed */ 79 } *rs; 80 81 /* Maybe be preserved in fork children, if _rs_allocate() decides. */ 82 static struct _rsx { 83 chacha_ctx rs_chacha; /* chacha context for random keystream */ 84 u_char rs_buf[RSBUFSZ]; /* keystream blocks */ 85 } *rsx; 86 87 static inline int _rs_allocate(struct _rs **, struct _rsx **); 88 static inline void _rs_forkdetect(void); 89 #include "arc4random.h" 90 91 static inline void _rs_rekey(u_char *dat, size_t datlen); 92 93 static inline void 94 _rs_init(u_char *buf, size_t n) 95 { 96 if (n < KEYSZ + IVSZ) 97 return; 98 99 if (rs == NULL) { 100 if (_rs_allocate(&rs, &rsx) == -1) 101 _exit(1); 102 } 103 104 chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8); 105 chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ); 106 } 107 108 static void 109 _rs_stir(void) 110 { 111 u_char rnd[KEYSZ + IVSZ]; 112 uint32_t rekey_fuzz = 0; 113 114 if (getentropy(rnd, sizeof rnd) == -1) 115 _getentropy_fail(); 116 117 if (!rs) 118 _rs_init(rnd, sizeof(rnd)); 119 else 120 _rs_rekey(rnd, sizeof(rnd)); 121 explicit_bzero(rnd, sizeof(rnd)); /* discard source seed */ 122 123 /* invalidate rs_buf */ 124 rs->rs_have = 0; 125 memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); 126 127 /* rekey interval should not be predictable */ 128 chacha_encrypt_bytes(&rsx->rs_chacha, (uint8_t *)&rekey_fuzz, 129 (uint8_t *)&rekey_fuzz, sizeof(rekey_fuzz)); 130 rs->rs_count = REKEY_BASE + (rekey_fuzz % REKEY_BASE); 131 } 132 133 static inline void 134 _rs_stir_if_needed(size_t len) 135 { 136 _rs_forkdetect(); 137 if (!rs || rs->rs_count <= len) 138 _rs_stir(); 139 if (rs->rs_count <= len) 140 rs->rs_count = 0; 141 else 142 rs->rs_count -= len; 143 } 144 145 static inline void 146 _rs_rekey(u_char *dat, size_t datlen) 147 { 148 #ifndef KEYSTREAM_ONLY 149 memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); 150 #endif 151 /* fill rs_buf with the keystream */ 152 chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf, 153 rsx->rs_buf, sizeof(rsx->rs_buf)); 154 /* mix in optional user provided data */ 155 if (dat) { 156 size_t i, m; 157 158 m = minimum(datlen, KEYSZ + IVSZ); 159 for (i = 0; i < m; i++) 160 rsx->rs_buf[i] ^= dat[i]; 161 } 162 /* immediately reinit for backtracking resistance */ 163 _rs_init(rsx->rs_buf, KEYSZ + IVSZ); 164 memset(rsx->rs_buf, 0, KEYSZ + IVSZ); 165 rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ; 166 } 167 168 static inline void 169 _rs_random_buf(void *_buf, size_t n) 170 { 171 u_char *buf = (u_char *)_buf; 172 u_char *keystream; 173 size_t m; 174 175 _rs_stir_if_needed(n); 176 while (n > 0) { 177 if (rs->rs_have > 0) { 178 m = minimum(n, rs->rs_have); 179 keystream = rsx->rs_buf + sizeof(rsx->rs_buf) 180 - rs->rs_have; 181 memcpy(buf, keystream, m); 182 memset(keystream, 0, m); 183 buf += m; 184 n -= m; 185 rs->rs_have -= m; 186 } 187 if (rs->rs_have == 0) 188 _rs_rekey(NULL, 0); 189 } 190 } 191 192 static inline void 193 _rs_random_u32(uint32_t *val) 194 { 195 u_char *keystream; 196 197 _rs_stir_if_needed(sizeof(*val)); 198 if (rs->rs_have < sizeof(*val)) 199 _rs_rekey(NULL, 0); 200 keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have; 201 memcpy(val, keystream, sizeof(*val)); 202 memset(keystream, 0, sizeof(*val)); 203 rs->rs_have -= sizeof(*val); 204 } 205 206 uint32_t 207 arc4random(void) 208 { 209 uint32_t val; 210 211 _ARC4_LOCK(); 212 _rs_random_u32(&val); 213 _ARC4_UNLOCK(); 214 return val; 215 } 216 DEF_WEAK(arc4random); 217 218 /* 219 * If we are providing arc4random, then we can provide a more efficient 220 * arc4random_buf(). 221 */ 222 # ifndef HAVE_ARC4RANDOM_BUF 223 void 224 arc4random_buf(void *buf, size_t n) 225 { 226 _ARC4_LOCK(); 227 _rs_random_buf(buf, n); 228 _ARC4_UNLOCK(); 229 } 230 DEF_WEAK(arc4random_buf); 231 # endif /* !HAVE_ARC4RANDOM_BUF */ 232 #endif /* !HAVE_ARC4RANDOM */ 233 234 /* arc4random_buf() that uses platform arc4random() */ 235 #if !defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_ARC4RANDOM) 236 void 237 arc4random_buf(void *_buf, size_t n) 238 { 239 size_t i; 240 u_int32_t r = 0; 241 char *buf = (char *)_buf; 242 243 for (i = 0; i < n; i++) { 244 if (i % 4 == 0) 245 r = arc4random(); 246 buf[i] = r & 0xff; 247 r >>= 8; 248 } 249 explicit_bzero(&r, sizeof(r)); 250 } 251 #endif /* !defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_ARC4RANDOM) */ 252 253