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