1*c1e80940SXin LI /* $OpenBSD: arc4random.c,v 1.54 2015/09/13 08:31:47 guenther 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> 6*c1e80940SXin LI * Copyright (c) 2013, Markus Friedl <markus@openbsd.org> 7*c1e80940SXin 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 /* 23*c1e80940SXin 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" 3083a03b38SAndrey A. Chernov #include <fcntl.h> 317a0789b4SDavid Schultz #include <limits.h> 325295209eSBrian Feldman #include <pthread.h> 33*c1e80940SXin LI #include <signal.h> 34*c1e80940SXin LI #include <stdint.h> 35*c1e80940SXin LI #include <stdlib.h> 36*c1e80940SXin LI #include <string.h> 37*c1e80940SXin LI #include <unistd.h> 38*c1e80940SXin LI #include <sys/types.h> 39*c1e80940SXin LI #include <sys/time.h> 405295209eSBrian Feldman 415295209eSBrian Feldman #include "libc_private.h" 42d201fe46SDaniel Eischen #include "un-namespace.h" 4383a03b38SAndrey A. Chernov 44*c1e80940SXin LI #define KEYSTREAM_ONLY 45*c1e80940SXin LI #include "chacha.c" 46*c1e80940SXin LI 47*c1e80940SXin LI #define minimum(a, b) ((a) < (b) ? (a) : (b)) 48*c1e80940SXin LI 49*c1e80940SXin LI #if defined(__GNUC__) || defined(_MSC_VER) 50c0b48470SDavid Schultz #define inline __inline 51*c1e80940SXin LI #else /* __GNUC__ || _MSC_VER */ 52c0b48470SDavid Schultz #define inline 53*c1e80940SXin LI #endif /* !__GNUC__ && !_MSC_VER */ 54c0b48470SDavid Schultz 55*c1e80940SXin LI #define KEYSZ 32 56*c1e80940SXin LI #define IVSZ 8 57*c1e80940SXin LI #define BLOCKSZ 64 58*c1e80940SXin LI #define RSBUFSZ (16*BLOCKSZ) 5983a03b38SAndrey A. Chernov 60*c1e80940SXin LI /* Marked INHERIT_ZERO, so zero'd out in fork children. */ 61*c1e80940SXin LI static struct _rs { 62*c1e80940SXin LI size_t rs_have; /* valid bytes at end of rs_buf */ 63*c1e80940SXin LI size_t rs_count; /* bytes till reseed */ 64*c1e80940SXin LI } *rs; 655295209eSBrian Feldman 66*c1e80940SXin LI /* Maybe be preserved in fork children, if _rs_allocate() decides. */ 67*c1e80940SXin LI static struct _rsx { 68*c1e80940SXin LI chacha_ctx rs_chacha; /* chacha context for random keystream */ 69*c1e80940SXin LI u_char rs_buf[RSBUFSZ]; /* keystream blocks */ 70*c1e80940SXin LI } *rsx; 715295209eSBrian Feldman 72*c1e80940SXin LI static inline int _rs_allocate(struct _rs **, struct _rsx **); 73*c1e80940SXin LI static inline void _rs_forkdetect(void); 74*c1e80940SXin LI #include "arc4random.h" 755295209eSBrian Feldman 76*c1e80940SXin LI static inline void _rs_rekey(u_char *dat, size_t datlen); 7760ce8b0eSDavid Schultz 7883a03b38SAndrey A. Chernov static inline void 79*c1e80940SXin LI _rs_init(u_char *buf, size_t n) 8083a03b38SAndrey A. Chernov { 81*c1e80940SXin LI if (n < KEYSZ + IVSZ) 82*c1e80940SXin LI return; 8383a03b38SAndrey A. Chernov 84*c1e80940SXin LI if (rs == NULL) { 85*c1e80940SXin LI if (_rs_allocate(&rs, &rsx) == -1) 8649a6e1baSEd Maste abort(); 8749a6e1baSEd Maste } 8883a03b38SAndrey A. Chernov 89*c1e80940SXin LI chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8); 90*c1e80940SXin LI chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ, NULL); 9183a03b38SAndrey A. Chernov } 9283a03b38SAndrey A. Chernov 937a0789b4SDavid Schultz static void 94*c1e80940SXin LI _rs_stir(void) 957a0789b4SDavid Schultz { 96*c1e80940SXin LI u_char rnd[KEYSZ + IVSZ]; 977a0789b4SDavid Schultz 98*c1e80940SXin LI if (getentropy(rnd, sizeof rnd) == -1) 99*c1e80940SXin LI _getentropy_fail(); 100*c1e80940SXin LI 101*c1e80940SXin LI if (!rs) 102*c1e80940SXin LI _rs_init(rnd, sizeof(rnd)); 103*c1e80940SXin LI else 104*c1e80940SXin LI _rs_rekey(rnd, sizeof(rnd)); 105*c1e80940SXin LI explicit_bzero(rnd, sizeof(rnd)); /* discard source seed */ 106*c1e80940SXin LI 107*c1e80940SXin LI /* invalidate rs_buf */ 108*c1e80940SXin LI rs->rs_have = 0; 109*c1e80940SXin LI memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); 110*c1e80940SXin LI 111*c1e80940SXin LI rs->rs_count = 1600000; 1127a0789b4SDavid Schultz } 1137a0789b4SDavid Schultz 114*c1e80940SXin LI static inline void 115*c1e80940SXin LI _rs_stir_if_needed(size_t len) 11683a03b38SAndrey A. Chernov { 117*c1e80940SXin LI _rs_forkdetect(); 118*c1e80940SXin LI if (!rs || rs->rs_count <= len) 119*c1e80940SXin LI _rs_stir(); 120*c1e80940SXin LI if (rs->rs_count <= len) 121*c1e80940SXin LI rs->rs_count = 0; 122*c1e80940SXin LI else 123*c1e80940SXin LI rs->rs_count -= len; 12483a03b38SAndrey A. Chernov } 12583a03b38SAndrey A. Chernov 126*c1e80940SXin LI static inline void 127*c1e80940SXin LI _rs_rekey(u_char *dat, size_t datlen) 12883a03b38SAndrey A. Chernov { 129*c1e80940SXin LI #ifndef KEYSTREAM_ONLY 130*c1e80940SXin LI memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); 131*c1e80940SXin LI #endif 132*c1e80940SXin LI /* fill rs_buf with the keystream */ 133*c1e80940SXin LI chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf, 134*c1e80940SXin LI rsx->rs_buf, sizeof(rsx->rs_buf)); 135*c1e80940SXin LI /* mix in optional user provided data */ 136*c1e80940SXin LI if (dat) { 137*c1e80940SXin LI size_t i, m; 138*c1e80940SXin LI 139*c1e80940SXin LI m = minimum(datlen, KEYSZ + IVSZ); 140*c1e80940SXin LI for (i = 0; i < m; i++) 141*c1e80940SXin LI rsx->rs_buf[i] ^= dat[i]; 142*c1e80940SXin LI } 143*c1e80940SXin LI /* immediately reinit for backtracking resistance */ 144*c1e80940SXin LI _rs_init(rsx->rs_buf, KEYSZ + IVSZ); 145*c1e80940SXin LI memset(rsx->rs_buf, 0, KEYSZ + IVSZ); 146*c1e80940SXin LI rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ; 14783a03b38SAndrey A. Chernov } 14883a03b38SAndrey A. Chernov 149*c1e80940SXin LI static inline void 150*c1e80940SXin LI _rs_random_buf(void *_buf, size_t n) 151bc6847e2SAndrey A. Chernov { 152bc6847e2SAndrey A. Chernov u_char *buf = (u_char *)_buf; 153*c1e80940SXin LI u_char *keystream; 154*c1e80940SXin LI size_t m; 155*c1e80940SXin LI 156*c1e80940SXin LI _rs_stir_if_needed(n); 157*c1e80940SXin LI while (n > 0) { 158*c1e80940SXin LI if (rs->rs_have > 0) { 159*c1e80940SXin LI m = minimum(n, rs->rs_have); 160*c1e80940SXin LI keystream = rsx->rs_buf + sizeof(rsx->rs_buf) 161*c1e80940SXin LI - rs->rs_have; 162*c1e80940SXin LI memcpy(buf, keystream, m); 163*c1e80940SXin LI memset(keystream, 0, m); 164*c1e80940SXin LI buf += m; 165*c1e80940SXin LI n -= m; 166*c1e80940SXin LI rs->rs_have -= m; 167bc6847e2SAndrey A. Chernov } 168*c1e80940SXin LI if (rs->rs_have == 0) 169*c1e80940SXin LI _rs_rekey(NULL, 0); 170*c1e80940SXin LI } 171*c1e80940SXin LI } 172*c1e80940SXin LI 173*c1e80940SXin LI static inline void 174*c1e80940SXin LI _rs_random_u32(uint32_t *val) 175*c1e80940SXin LI { 176*c1e80940SXin LI u_char *keystream; 177*c1e80940SXin LI 178*c1e80940SXin LI _rs_stir_if_needed(sizeof(*val)); 179*c1e80940SXin LI if (rs->rs_have < sizeof(*val)) 180*c1e80940SXin LI _rs_rekey(NULL, 0); 181*c1e80940SXin LI keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have; 182*c1e80940SXin LI memcpy(val, keystream, sizeof(*val)); 183*c1e80940SXin LI memset(keystream, 0, sizeof(*val)); 184*c1e80940SXin LI rs->rs_have -= sizeof(*val); 185*c1e80940SXin LI } 186*c1e80940SXin LI 187*c1e80940SXin LI uint32_t 188*c1e80940SXin LI arc4random(void) 189*c1e80940SXin LI { 190*c1e80940SXin LI uint32_t val; 191*c1e80940SXin LI 192*c1e80940SXin LI _ARC4_LOCK(); 193*c1e80940SXin LI _rs_random_u32(&val); 194*c1e80940SXin LI _ARC4_UNLOCK(); 195*c1e80940SXin LI return val; 196*c1e80940SXin LI } 197*c1e80940SXin LI 198*c1e80940SXin LI void 199*c1e80940SXin LI arc4random_buf(void *buf, size_t n) 200*c1e80940SXin LI { 201*c1e80940SXin LI _ARC4_LOCK(); 202*c1e80940SXin LI _rs_random_buf(buf, n); 203c0b48470SDavid Schultz _ARC4_UNLOCK(); 204bc6847e2SAndrey A. Chernov } 205