1c1e80940SXin 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> 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" 3083a03b38SAndrey A. Chernov #include <fcntl.h> 317a0789b4SDavid Schultz #include <limits.h> 325295209eSBrian Feldman #include <pthread.h> 33c1e80940SXin LI #include <signal.h> 34c1e80940SXin LI #include <stdint.h> 35c1e80940SXin LI #include <stdlib.h> 36c1e80940SXin LI #include <string.h> 37c1e80940SXin LI #include <unistd.h> 38c1e80940SXin LI #include <sys/types.h> 39c1e80940SXin LI #include <sys/time.h> 405295209eSBrian Feldman 415295209eSBrian Feldman #include "libc_private.h" 42d201fe46SDaniel Eischen #include "un-namespace.h" 4383a03b38SAndrey A. Chernov 44243e0943SConrad Meyer #define CHACHA_EMBED 45c1e80940SXin LI #define KEYSTREAM_ONLY 46c1e80940SXin LI #include "chacha.c" 47c1e80940SXin LI 48c1e80940SXin LI #define minimum(a, b) ((a) < (b) ? (a) : (b)) 49c1e80940SXin LI 50c1e80940SXin LI #if defined(__GNUC__) || defined(_MSC_VER) 51c0b48470SDavid Schultz #define inline __inline 52c1e80940SXin LI #else /* __GNUC__ || _MSC_VER */ 53c0b48470SDavid Schultz #define inline 54c1e80940SXin LI #endif /* !__GNUC__ && !_MSC_VER */ 55c0b48470SDavid Schultz 56c1e80940SXin LI #define KEYSZ 32 57c1e80940SXin LI #define IVSZ 8 58c1e80940SXin LI #define BLOCKSZ 64 59c1e80940SXin LI #define RSBUFSZ (16*BLOCKSZ) 6083a03b38SAndrey A. Chernov 61c1e80940SXin LI /* Marked INHERIT_ZERO, so zero'd out in fork children. */ 62c1e80940SXin LI static struct _rs { 63c1e80940SXin LI size_t rs_have; /* valid bytes at end of rs_buf */ 64c1e80940SXin LI size_t rs_count; /* bytes till reseed */ 65c1e80940SXin LI } *rs; 665295209eSBrian Feldman 67c1e80940SXin LI /* Maybe be preserved in fork children, if _rs_allocate() decides. */ 68c1e80940SXin LI static struct _rsx { 69c1e80940SXin LI chacha_ctx rs_chacha; /* chacha context for random keystream */ 70c1e80940SXin LI u_char rs_buf[RSBUFSZ]; /* keystream blocks */ 71c1e80940SXin LI } *rsx; 725295209eSBrian Feldman 73c1e80940SXin LI static inline int _rs_allocate(struct _rs **, struct _rsx **); 74c1e80940SXin LI static inline void _rs_forkdetect(void); 75c1e80940SXin LI #include "arc4random.h" 765295209eSBrian Feldman 77c1e80940SXin LI static inline void _rs_rekey(u_char *dat, size_t datlen); 7860ce8b0eSDavid Schultz 7983a03b38SAndrey A. Chernov static inline void 80c1e80940SXin LI _rs_init(u_char *buf, size_t n) 8183a03b38SAndrey A. Chernov { 82c1e80940SXin LI if (n < KEYSZ + IVSZ) 83c1e80940SXin LI return; 8483a03b38SAndrey A. Chernov 85c1e80940SXin LI if (rs == NULL) { 86c1e80940SXin LI if (_rs_allocate(&rs, &rsx) == -1) 8749a6e1baSEd Maste abort(); 8849a6e1baSEd Maste } 8983a03b38SAndrey A. Chernov 90c1e80940SXin LI chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8); 91c1e80940SXin LI chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ, NULL); 9283a03b38SAndrey A. Chernov } 9383a03b38SAndrey A. Chernov 947a0789b4SDavid Schultz static void 95c1e80940SXin LI _rs_stir(void) 967a0789b4SDavid Schultz { 97c1e80940SXin LI u_char rnd[KEYSZ + IVSZ]; 987a0789b4SDavid Schultz 99c1e80940SXin LI if (getentropy(rnd, sizeof rnd) == -1) 100c1e80940SXin LI _getentropy_fail(); 101c1e80940SXin LI 102c1e80940SXin LI if (!rs) 103c1e80940SXin LI _rs_init(rnd, sizeof(rnd)); 104c1e80940SXin LI else 105c1e80940SXin LI _rs_rekey(rnd, sizeof(rnd)); 106c1e80940SXin LI explicit_bzero(rnd, sizeof(rnd)); /* discard source seed */ 107c1e80940SXin LI 108c1e80940SXin LI /* invalidate rs_buf */ 109c1e80940SXin LI rs->rs_have = 0; 110c1e80940SXin LI memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); 111c1e80940SXin LI 112c1e80940SXin LI rs->rs_count = 1600000; 1137a0789b4SDavid Schultz } 1147a0789b4SDavid Schultz 115c1e80940SXin LI static inline void 116c1e80940SXin LI _rs_stir_if_needed(size_t len) 11783a03b38SAndrey A. Chernov { 118c1e80940SXin LI _rs_forkdetect(); 119c1e80940SXin LI if (!rs || rs->rs_count <= len) 120c1e80940SXin LI _rs_stir(); 121c1e80940SXin LI if (rs->rs_count <= len) 122c1e80940SXin LI rs->rs_count = 0; 123c1e80940SXin LI else 124c1e80940SXin LI rs->rs_count -= len; 12583a03b38SAndrey A. Chernov } 12683a03b38SAndrey A. Chernov 127c1e80940SXin LI static inline void 128c1e80940SXin LI _rs_rekey(u_char *dat, size_t datlen) 12983a03b38SAndrey A. Chernov { 130c1e80940SXin LI #ifndef KEYSTREAM_ONLY 131c1e80940SXin LI memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); 132c1e80940SXin LI #endif 133c1e80940SXin LI /* fill rs_buf with the keystream */ 134c1e80940SXin LI chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf, 135c1e80940SXin LI rsx->rs_buf, sizeof(rsx->rs_buf)); 136c1e80940SXin LI /* mix in optional user provided data */ 137c1e80940SXin LI if (dat) { 138c1e80940SXin LI size_t i, m; 139c1e80940SXin LI 140c1e80940SXin LI m = minimum(datlen, KEYSZ + IVSZ); 141c1e80940SXin LI for (i = 0; i < m; i++) 142c1e80940SXin LI rsx->rs_buf[i] ^= dat[i]; 143c1e80940SXin LI } 144c1e80940SXin LI /* immediately reinit for backtracking resistance */ 145c1e80940SXin LI _rs_init(rsx->rs_buf, KEYSZ + IVSZ); 146c1e80940SXin LI memset(rsx->rs_buf, 0, KEYSZ + IVSZ); 147c1e80940SXin LI rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ; 14883a03b38SAndrey A. Chernov } 14983a03b38SAndrey A. Chernov 150c1e80940SXin LI static inline void 151c1e80940SXin LI _rs_random_buf(void *_buf, size_t n) 152bc6847e2SAndrey A. Chernov { 153bc6847e2SAndrey A. Chernov u_char *buf = (u_char *)_buf; 154c1e80940SXin LI u_char *keystream; 155c1e80940SXin LI size_t m; 156c1e80940SXin LI 157c1e80940SXin LI _rs_stir_if_needed(n); 158c1e80940SXin LI while (n > 0) { 159c1e80940SXin LI if (rs->rs_have > 0) { 160c1e80940SXin LI m = minimum(n, rs->rs_have); 161c1e80940SXin LI keystream = rsx->rs_buf + sizeof(rsx->rs_buf) 162c1e80940SXin LI - rs->rs_have; 163c1e80940SXin LI memcpy(buf, keystream, m); 164c1e80940SXin LI memset(keystream, 0, m); 165c1e80940SXin LI buf += m; 166c1e80940SXin LI n -= m; 167c1e80940SXin LI rs->rs_have -= m; 168bc6847e2SAndrey A. Chernov } 169c1e80940SXin LI if (rs->rs_have == 0) 170c1e80940SXin LI _rs_rekey(NULL, 0); 171c1e80940SXin LI } 172c1e80940SXin LI } 173c1e80940SXin LI 174c1e80940SXin LI static inline void 175c1e80940SXin LI _rs_random_u32(uint32_t *val) 176c1e80940SXin LI { 177c1e80940SXin LI u_char *keystream; 178c1e80940SXin LI 179c1e80940SXin LI _rs_stir_if_needed(sizeof(*val)); 180c1e80940SXin LI if (rs->rs_have < sizeof(*val)) 181c1e80940SXin LI _rs_rekey(NULL, 0); 182c1e80940SXin LI keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have; 183c1e80940SXin LI memcpy(val, keystream, sizeof(*val)); 184c1e80940SXin LI memset(keystream, 0, sizeof(*val)); 185c1e80940SXin LI rs->rs_have -= sizeof(*val); 186c1e80940SXin LI } 187c1e80940SXin LI 188c1e80940SXin LI uint32_t 189c1e80940SXin LI arc4random(void) 190c1e80940SXin LI { 191c1e80940SXin LI uint32_t val; 192c1e80940SXin LI 193c1e80940SXin LI _ARC4_LOCK(); 194c1e80940SXin LI _rs_random_u32(&val); 195c1e80940SXin LI _ARC4_UNLOCK(); 196c1e80940SXin LI return val; 197c1e80940SXin LI } 198c1e80940SXin LI 199c1e80940SXin LI void 200c1e80940SXin LI arc4random_buf(void *buf, size_t n) 201c1e80940SXin LI { 202c1e80940SXin LI _ARC4_LOCK(); 203c1e80940SXin LI _rs_random_buf(buf, n); 204c0b48470SDavid Schultz _ARC4_UNLOCK(); 205bc6847e2SAndrey A. Chernov } 206