1d25a1430SXin LI /* $OpenBSD: arc4random.c,v 1.55 2019/03/24 17:56:54 deraadt Exp $ */ 2c0b48470SDavid Schultz 383a03b38SAndrey A. Chernov /* 4860c4e58SAndrey A. Chernov * Copyright (c) 1996, David Mazieres <dm@uun.org> 5860c4e58SAndrey A. Chernov * Copyright (c) 2008, Damien Miller <djm@openbsd.org> 6c1e80940SXin LI * Copyright (c) 2013, Markus Friedl <markus@openbsd.org> 7c1e80940SXin LI * Copyright (c) 2014, Theo de Raadt <deraadt@openbsd.org> 883a03b38SAndrey A. Chernov * 9860c4e58SAndrey A. Chernov * Permission to use, copy, modify, and distribute this software for any 10860c4e58SAndrey A. Chernov * purpose with or without fee is hereby granted, provided that the above 11860c4e58SAndrey A. Chernov * copyright notice and this permission notice appear in all copies. 12860c4e58SAndrey A. Chernov * 13860c4e58SAndrey A. Chernov * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14860c4e58SAndrey A. Chernov * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15860c4e58SAndrey A. Chernov * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16860c4e58SAndrey A. Chernov * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17860c4e58SAndrey A. Chernov * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18860c4e58SAndrey A. Chernov * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19860c4e58SAndrey A. Chernov * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 2083a03b38SAndrey A. Chernov */ 2183a03b38SAndrey A. Chernov 2283a03b38SAndrey A. Chernov /* 23c1e80940SXin LI * ChaCha based random number generator for OpenBSD. 2483a03b38SAndrey A. Chernov */ 2583a03b38SAndrey A. Chernov 26333fc21eSDavid E. O'Brien #include <sys/cdefs.h> 27333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 28333fc21eSDavid E. O'Brien 29d201fe46SDaniel Eischen #include "namespace.h" 30*f8e8a06dSConrad Meyer #if defined(__FreeBSD__) 31*f8e8a06dSConrad Meyer #include <assert.h> 32*f8e8a06dSConrad Meyer #endif 3383a03b38SAndrey A. Chernov #include <fcntl.h> 347a0789b4SDavid Schultz #include <limits.h> 355295209eSBrian Feldman #include <pthread.h> 36c1e80940SXin LI #include <signal.h> 37c1e80940SXin LI #include <stdint.h> 38c1e80940SXin LI #include <stdlib.h> 39c1e80940SXin LI #include <string.h> 40c1e80940SXin LI #include <unistd.h> 41c1e80940SXin LI #include <sys/types.h> 42c1e80940SXin LI #include <sys/time.h> 435295209eSBrian Feldman 445295209eSBrian Feldman #include "libc_private.h" 45d201fe46SDaniel Eischen #include "un-namespace.h" 4683a03b38SAndrey A. Chernov 47243e0943SConrad Meyer #define CHACHA_EMBED 48c1e80940SXin LI #define KEYSTREAM_ONLY 49c1e80940SXin LI #include "chacha.c" 50c1e80940SXin LI 51c1e80940SXin LI #define minimum(a, b) ((a) < (b) ? (a) : (b)) 52c1e80940SXin LI 53c1e80940SXin LI #if defined(__GNUC__) || defined(_MSC_VER) 54c0b48470SDavid Schultz #define inline __inline 55c1e80940SXin LI #else /* __GNUC__ || _MSC_VER */ 56c0b48470SDavid Schultz #define inline 57c1e80940SXin LI #endif /* !__GNUC__ && !_MSC_VER */ 58c0b48470SDavid Schultz 59c1e80940SXin LI #define KEYSZ 32 60c1e80940SXin LI #define IVSZ 8 61c1e80940SXin LI #define BLOCKSZ 64 62c1e80940SXin LI #define RSBUFSZ (16*BLOCKSZ) 6383a03b38SAndrey A. Chernov 64c1e80940SXin LI /* Marked INHERIT_ZERO, so zero'd out in fork children. */ 65c1e80940SXin LI static struct _rs { 66c1e80940SXin LI size_t rs_have; /* valid bytes at end of rs_buf */ 67c1e80940SXin LI size_t rs_count; /* bytes till reseed */ 68c1e80940SXin LI } *rs; 695295209eSBrian Feldman 70c1e80940SXin LI /* Maybe be preserved in fork children, if _rs_allocate() decides. */ 71c1e80940SXin LI static struct _rsx { 72c1e80940SXin LI chacha_ctx rs_chacha; /* chacha context for random keystream */ 73c1e80940SXin LI u_char rs_buf[RSBUFSZ]; /* keystream blocks */ 74*f8e8a06dSConrad Meyer #ifdef __FreeBSD__ 75*f8e8a06dSConrad Meyer uint32_t rs_seed_generation; /* 32-bit userspace RNG version */ 76*f8e8a06dSConrad Meyer #endif 77c1e80940SXin LI } *rsx; 785295209eSBrian Feldman 79c1e80940SXin LI static inline int _rs_allocate(struct _rs **, struct _rsx **); 80c1e80940SXin LI static inline void _rs_forkdetect(void); 81c1e80940SXin LI #include "arc4random.h" 825295209eSBrian Feldman 83c1e80940SXin LI static inline void _rs_rekey(u_char *dat, size_t datlen); 8460ce8b0eSDavid Schultz 8583a03b38SAndrey A. Chernov static inline void 86c1e80940SXin LI _rs_init(u_char *buf, size_t n) 8783a03b38SAndrey A. Chernov { 88c1e80940SXin LI if (n < KEYSZ + IVSZ) 89c1e80940SXin LI return; 9083a03b38SAndrey A. Chernov 91c1e80940SXin LI if (rs == NULL) { 92c1e80940SXin LI if (_rs_allocate(&rs, &rsx) == -1) 93d25a1430SXin LI _exit(1); 9449a6e1baSEd Maste } 9583a03b38SAndrey A. Chernov 96c1e80940SXin LI chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8); 97c1e80940SXin LI chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ, NULL); 9883a03b38SAndrey A. Chernov } 9983a03b38SAndrey A. Chernov 1007a0789b4SDavid Schultz static void 101c1e80940SXin LI _rs_stir(void) 1027a0789b4SDavid Schultz { 103c1e80940SXin LI u_char rnd[KEYSZ + IVSZ]; 1047a0789b4SDavid Schultz 105*f8e8a06dSConrad Meyer #if defined(__FreeBSD__) 106*f8e8a06dSConrad Meyer bool need_init; 107*f8e8a06dSConrad Meyer 108*f8e8a06dSConrad Meyer /* 109*f8e8a06dSConrad Meyer * De-couple allocation (which locates the vdso_fxrngp pointer in 110*f8e8a06dSConrad Meyer * auxinfo) from initialization. This allows us to read the root seed 111*f8e8a06dSConrad Meyer * version before we fetch system entropy, maintaining the invariant 112*f8e8a06dSConrad Meyer * that the PRF was seeded with entropy from rs_seed_generation or a 113*f8e8a06dSConrad Meyer * later generation. But never seeded from an earlier generation. 114*f8e8a06dSConrad Meyer * This invariant prevents us from missing a root reseed event. 115*f8e8a06dSConrad Meyer */ 116*f8e8a06dSConrad Meyer need_init = false; 117*f8e8a06dSConrad Meyer if (rs == NULL) { 118*f8e8a06dSConrad Meyer if (_rs_allocate(&rs, &rsx) == -1) 119*f8e8a06dSConrad Meyer abort(); 120*f8e8a06dSConrad Meyer need_init = true; 121*f8e8a06dSConrad Meyer } 122*f8e8a06dSConrad Meyer /* 123*f8e8a06dSConrad Meyer * Transition period: new userspace on old kernel. This should become 124*f8e8a06dSConrad Meyer * a hard error at some point, if the scheme is adopted. 125*f8e8a06dSConrad Meyer */ 126*f8e8a06dSConrad Meyer if (vdso_fxrngp != NULL) 127*f8e8a06dSConrad Meyer rsx->rs_seed_generation = 128*f8e8a06dSConrad Meyer fxrng_load_acq_generation(&vdso_fxrngp->fx_generation32); 129*f8e8a06dSConrad Meyer #endif 130*f8e8a06dSConrad Meyer 131c1e80940SXin LI if (getentropy(rnd, sizeof rnd) == -1) 132c1e80940SXin LI _getentropy_fail(); 133c1e80940SXin LI 134*f8e8a06dSConrad Meyer #if !defined(__FreeBSD__) 135c1e80940SXin LI if (!rs) 136c1e80940SXin LI _rs_init(rnd, sizeof(rnd)); 137*f8e8a06dSConrad Meyer #else /* __FreeBSD__ */ 138*f8e8a06dSConrad Meyer assert(rs != NULL); 139*f8e8a06dSConrad Meyer if (need_init) 140*f8e8a06dSConrad Meyer _rs_init(rnd, sizeof(rnd)); 141*f8e8a06dSConrad Meyer #endif 142c1e80940SXin LI else 143c1e80940SXin LI _rs_rekey(rnd, sizeof(rnd)); 144c1e80940SXin LI explicit_bzero(rnd, sizeof(rnd)); /* discard source seed */ 145c1e80940SXin LI 146c1e80940SXin LI /* invalidate rs_buf */ 147c1e80940SXin LI rs->rs_have = 0; 148c1e80940SXin LI memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); 149c1e80940SXin LI 150c1e80940SXin LI rs->rs_count = 1600000; 1517a0789b4SDavid Schultz } 1527a0789b4SDavid Schultz 153c1e80940SXin LI static inline void 154c1e80940SXin LI _rs_stir_if_needed(size_t len) 15583a03b38SAndrey A. Chernov { 156c1e80940SXin LI _rs_forkdetect(); 157c1e80940SXin LI if (!rs || rs->rs_count <= len) 158c1e80940SXin LI _rs_stir(); 159c1e80940SXin LI if (rs->rs_count <= len) 160c1e80940SXin LI rs->rs_count = 0; 161c1e80940SXin LI else 162c1e80940SXin LI rs->rs_count -= len; 16383a03b38SAndrey A. Chernov } 16483a03b38SAndrey A. Chernov 165c1e80940SXin LI static inline void 166c1e80940SXin LI _rs_rekey(u_char *dat, size_t datlen) 16783a03b38SAndrey A. Chernov { 168c1e80940SXin LI #ifndef KEYSTREAM_ONLY 169c1e80940SXin LI memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); 170c1e80940SXin LI #endif 171c1e80940SXin LI /* fill rs_buf with the keystream */ 172c1e80940SXin LI chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf, 173c1e80940SXin LI rsx->rs_buf, sizeof(rsx->rs_buf)); 174c1e80940SXin LI /* mix in optional user provided data */ 175c1e80940SXin LI if (dat) { 176c1e80940SXin LI size_t i, m; 177c1e80940SXin LI 178c1e80940SXin LI m = minimum(datlen, KEYSZ + IVSZ); 179c1e80940SXin LI for (i = 0; i < m; i++) 180c1e80940SXin LI rsx->rs_buf[i] ^= dat[i]; 181c1e80940SXin LI } 182c1e80940SXin LI /* immediately reinit for backtracking resistance */ 183c1e80940SXin LI _rs_init(rsx->rs_buf, KEYSZ + IVSZ); 184c1e80940SXin LI memset(rsx->rs_buf, 0, KEYSZ + IVSZ); 185c1e80940SXin LI rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ; 18683a03b38SAndrey A. Chernov } 18783a03b38SAndrey A. Chernov 188c1e80940SXin LI static inline void 189c1e80940SXin LI _rs_random_buf(void *_buf, size_t n) 190bc6847e2SAndrey A. Chernov { 191bc6847e2SAndrey A. Chernov u_char *buf = (u_char *)_buf; 192c1e80940SXin LI u_char *keystream; 193c1e80940SXin LI size_t m; 194c1e80940SXin LI 195c1e80940SXin LI _rs_stir_if_needed(n); 196c1e80940SXin LI while (n > 0) { 197c1e80940SXin LI if (rs->rs_have > 0) { 198c1e80940SXin LI m = minimum(n, rs->rs_have); 199c1e80940SXin LI keystream = rsx->rs_buf + sizeof(rsx->rs_buf) 200c1e80940SXin LI - rs->rs_have; 201c1e80940SXin LI memcpy(buf, keystream, m); 202c1e80940SXin LI memset(keystream, 0, m); 203c1e80940SXin LI buf += m; 204c1e80940SXin LI n -= m; 205c1e80940SXin LI rs->rs_have -= m; 206bc6847e2SAndrey A. Chernov } 207c1e80940SXin LI if (rs->rs_have == 0) 208c1e80940SXin LI _rs_rekey(NULL, 0); 209c1e80940SXin LI } 210c1e80940SXin LI } 211c1e80940SXin LI 212c1e80940SXin LI static inline void 213c1e80940SXin LI _rs_random_u32(uint32_t *val) 214c1e80940SXin LI { 215c1e80940SXin LI u_char *keystream; 216c1e80940SXin LI 217c1e80940SXin LI _rs_stir_if_needed(sizeof(*val)); 218c1e80940SXin LI if (rs->rs_have < sizeof(*val)) 219c1e80940SXin LI _rs_rekey(NULL, 0); 220c1e80940SXin LI keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have; 221c1e80940SXin LI memcpy(val, keystream, sizeof(*val)); 222c1e80940SXin LI memset(keystream, 0, sizeof(*val)); 223c1e80940SXin LI rs->rs_have -= sizeof(*val); 224c1e80940SXin LI } 225c1e80940SXin LI 226c1e80940SXin LI uint32_t 227c1e80940SXin LI arc4random(void) 228c1e80940SXin LI { 229c1e80940SXin LI uint32_t val; 230c1e80940SXin LI 231c1e80940SXin LI _ARC4_LOCK(); 232c1e80940SXin LI _rs_random_u32(&val); 233c1e80940SXin LI _ARC4_UNLOCK(); 234c1e80940SXin LI return val; 235c1e80940SXin LI } 236c1e80940SXin LI 237c1e80940SXin LI void 238c1e80940SXin LI arc4random_buf(void *buf, size_t n) 239c1e80940SXin LI { 240c1e80940SXin LI _ARC4_LOCK(); 241c1e80940SXin LI _rs_random_buf(buf, n); 242c0b48470SDavid Schultz _ARC4_UNLOCK(); 243bc6847e2SAndrey A. Chernov } 244