1*ff825849SDag-Erling Smørgrav /* $OpenBSD: arc4random.c,v 1.41 2014/07/12 13:24:54 deraadt Exp $ */ 2*ff825849SDag-Erling Smørgrav 3*ff825849SDag-Erling Smørgrav /* 4*ff825849SDag-Erling Smørgrav * Copyright (c) 1996, David Mazieres <dm@uun.org> 5*ff825849SDag-Erling Smørgrav * Copyright (c) 2008, Damien Miller <djm@openbsd.org> 6*ff825849SDag-Erling Smørgrav * Copyright (c) 2013, Markus Friedl <markus@openbsd.org> 7*ff825849SDag-Erling Smørgrav * 8*ff825849SDag-Erling Smørgrav * Permission to use, copy, modify, and distribute this software for any 9*ff825849SDag-Erling Smørgrav * purpose with or without fee is hereby granted, provided that the above 10*ff825849SDag-Erling Smørgrav * copyright notice and this permission notice appear in all copies. 11*ff825849SDag-Erling Smørgrav * 12*ff825849SDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13*ff825849SDag-Erling Smørgrav * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14*ff825849SDag-Erling Smørgrav * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15*ff825849SDag-Erling Smørgrav * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16*ff825849SDag-Erling Smørgrav * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17*ff825849SDag-Erling Smørgrav * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18*ff825849SDag-Erling Smørgrav * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19*ff825849SDag-Erling Smørgrav */ 20*ff825849SDag-Erling Smørgrav #include "config.h" 21*ff825849SDag-Erling Smørgrav 22*ff825849SDag-Erling Smørgrav /* 23*ff825849SDag-Erling Smørgrav * ChaCha based random number generator for OpenBSD. 24*ff825849SDag-Erling Smørgrav */ 25*ff825849SDag-Erling Smørgrav 26*ff825849SDag-Erling Smørgrav #include <fcntl.h> 27*ff825849SDag-Erling Smørgrav #include <limits.h> 28*ff825849SDag-Erling Smørgrav #include <signal.h> 29*ff825849SDag-Erling Smørgrav #include <stdint.h> 30*ff825849SDag-Erling Smørgrav #include <stdlib.h> 31*ff825849SDag-Erling Smørgrav #include <string.h> 32*ff825849SDag-Erling Smørgrav #include <unistd.h> 33*ff825849SDag-Erling Smørgrav #include <sys/types.h> 34*ff825849SDag-Erling Smørgrav #include <sys/param.h> 35*ff825849SDag-Erling Smørgrav #include <sys/time.h> 36*ff825849SDag-Erling Smørgrav #ifndef UB_ON_WINDOWS 37*ff825849SDag-Erling Smørgrav #include <sys/mman.h> 38*ff825849SDag-Erling Smørgrav #endif 39*ff825849SDag-Erling Smørgrav 40*ff825849SDag-Erling Smørgrav #define KEYSTREAM_ONLY 41*ff825849SDag-Erling Smørgrav #include "chacha_private.h" 42*ff825849SDag-Erling Smørgrav 43*ff825849SDag-Erling Smørgrav #define arc4_min(a, b) ((a) < (b) ? (a) : (b)) 44*ff825849SDag-Erling Smørgrav #ifdef __GNUC__ 45*ff825849SDag-Erling Smørgrav #define inline __inline 46*ff825849SDag-Erling Smørgrav #else /* !__GNUC__ */ 47*ff825849SDag-Erling Smørgrav #define inline 48*ff825849SDag-Erling Smørgrav #endif /* !__GNUC__ */ 49*ff825849SDag-Erling Smørgrav 50*ff825849SDag-Erling Smørgrav #define KEYSZ 32 51*ff825849SDag-Erling Smørgrav #define IVSZ 8 52*ff825849SDag-Erling Smørgrav #define BLOCKSZ 64 53*ff825849SDag-Erling Smørgrav #define RSBUFSZ (16*BLOCKSZ) 54*ff825849SDag-Erling Smørgrav 55*ff825849SDag-Erling Smørgrav /* Marked MAP_INHERIT_ZERO, so zero'd out in fork children. */ 56*ff825849SDag-Erling Smørgrav static struct { 57*ff825849SDag-Erling Smørgrav size_t rs_have; /* valid bytes at end of rs_buf */ 58*ff825849SDag-Erling Smørgrav size_t rs_count; /* bytes till reseed */ 59*ff825849SDag-Erling Smørgrav } *rs; 60*ff825849SDag-Erling Smørgrav 61*ff825849SDag-Erling Smørgrav /* Preserved in fork children. */ 62*ff825849SDag-Erling Smørgrav static struct { 63*ff825849SDag-Erling Smørgrav chacha_ctx rs_chacha; /* chacha context for random keystream */ 64*ff825849SDag-Erling Smørgrav u_char rs_buf[RSBUFSZ]; /* keystream blocks */ 65*ff825849SDag-Erling Smørgrav } *rsx; 66*ff825849SDag-Erling Smørgrav 67*ff825849SDag-Erling Smørgrav static inline void _rs_rekey(u_char *dat, size_t datlen); 68*ff825849SDag-Erling Smørgrav 69*ff825849SDag-Erling Smørgrav static inline void 70*ff825849SDag-Erling Smørgrav _rs_init(u_char *buf, size_t n) 71*ff825849SDag-Erling Smørgrav { 72*ff825849SDag-Erling Smørgrav if (n < KEYSZ + IVSZ) 73*ff825849SDag-Erling Smørgrav return; 74*ff825849SDag-Erling Smørgrav 75*ff825849SDag-Erling Smørgrav if (rs == NULL) { 76*ff825849SDag-Erling Smørgrav #ifndef UB_ON_WINDOWS 77*ff825849SDag-Erling Smørgrav if ((rs = mmap(NULL, sizeof(*rs), PROT_READ|PROT_WRITE, 78*ff825849SDag-Erling Smørgrav MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) 79*ff825849SDag-Erling Smørgrav abort(); 80*ff825849SDag-Erling Smørgrav #ifdef MAP_INHERIT_ZERO 81*ff825849SDag-Erling Smørgrav if (minherit(rs, sizeof(*rs), MAP_INHERIT_ZERO) == -1) 82*ff825849SDag-Erling Smørgrav abort(); 83*ff825849SDag-Erling Smørgrav #endif 84*ff825849SDag-Erling Smørgrav #else /* WINDOWS */ 85*ff825849SDag-Erling Smørgrav rs = malloc(sizeof(*rs)); 86*ff825849SDag-Erling Smørgrav if(!rs) 87*ff825849SDag-Erling Smørgrav abort(); 88*ff825849SDag-Erling Smørgrav #endif 89*ff825849SDag-Erling Smørgrav } 90*ff825849SDag-Erling Smørgrav if (rsx == NULL) { 91*ff825849SDag-Erling Smørgrav #ifndef UB_ON_WINDOWS 92*ff825849SDag-Erling Smørgrav if ((rsx = mmap(NULL, sizeof(*rsx), PROT_READ|PROT_WRITE, 93*ff825849SDag-Erling Smørgrav MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) 94*ff825849SDag-Erling Smørgrav abort(); 95*ff825849SDag-Erling Smørgrav #else /* WINDOWS */ 96*ff825849SDag-Erling Smørgrav rsx = malloc(sizeof(*rsx)); 97*ff825849SDag-Erling Smørgrav if(!rsx) 98*ff825849SDag-Erling Smørgrav abort(); 99*ff825849SDag-Erling Smørgrav #endif 100*ff825849SDag-Erling Smørgrav } 101*ff825849SDag-Erling Smørgrav 102*ff825849SDag-Erling Smørgrav chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8, 0); 103*ff825849SDag-Erling Smørgrav chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ); 104*ff825849SDag-Erling Smørgrav } 105*ff825849SDag-Erling Smørgrav 106*ff825849SDag-Erling Smørgrav static void 107*ff825849SDag-Erling Smørgrav _rs_stir(void) 108*ff825849SDag-Erling Smørgrav { 109*ff825849SDag-Erling Smørgrav u_char rnd[KEYSZ + IVSZ]; 110*ff825849SDag-Erling Smørgrav 111*ff825849SDag-Erling Smørgrav if (getentropy(rnd, sizeof rnd) == -1) { 112*ff825849SDag-Erling Smørgrav #ifdef SIGKILL 113*ff825849SDag-Erling Smørgrav raise(SIGKILL); 114*ff825849SDag-Erling Smørgrav #else 115*ff825849SDag-Erling Smørgrav exit(9); /* windows */ 116*ff825849SDag-Erling Smørgrav #endif 117*ff825849SDag-Erling Smørgrav } 118*ff825849SDag-Erling Smørgrav 119*ff825849SDag-Erling Smørgrav if (!rs) 120*ff825849SDag-Erling Smørgrav _rs_init(rnd, sizeof(rnd)); 121*ff825849SDag-Erling Smørgrav else 122*ff825849SDag-Erling Smørgrav _rs_rekey(rnd, sizeof(rnd)); 123*ff825849SDag-Erling Smørgrav explicit_bzero(rnd, sizeof(rnd)); /* discard source seed */ 124*ff825849SDag-Erling Smørgrav 125*ff825849SDag-Erling Smørgrav /* invalidate rs_buf */ 126*ff825849SDag-Erling Smørgrav rs->rs_have = 0; 127*ff825849SDag-Erling Smørgrav memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); 128*ff825849SDag-Erling Smørgrav 129*ff825849SDag-Erling Smørgrav rs->rs_count = 1600000; 130*ff825849SDag-Erling Smørgrav } 131*ff825849SDag-Erling Smørgrav 132*ff825849SDag-Erling Smørgrav static inline void 133*ff825849SDag-Erling Smørgrav _rs_stir_if_needed(size_t len) 134*ff825849SDag-Erling Smørgrav { 135*ff825849SDag-Erling Smørgrav #ifndef MAP_INHERIT_ZERO 136*ff825849SDag-Erling Smørgrav static pid_t _rs_pid = 0; 137*ff825849SDag-Erling Smørgrav pid_t pid = getpid(); 138*ff825849SDag-Erling Smørgrav 139*ff825849SDag-Erling Smørgrav /* If a system lacks MAP_INHERIT_ZERO, resort to getpid() */ 140*ff825849SDag-Erling Smørgrav if (_rs_pid == 0 || _rs_pid != pid) { 141*ff825849SDag-Erling Smørgrav _rs_pid = pid; 142*ff825849SDag-Erling Smørgrav if (rs) 143*ff825849SDag-Erling Smørgrav rs->rs_count = 0; 144*ff825849SDag-Erling Smørgrav } 145*ff825849SDag-Erling Smørgrav #endif 146*ff825849SDag-Erling Smørgrav if (!rs || rs->rs_count <= len) 147*ff825849SDag-Erling Smørgrav _rs_stir(); 148*ff825849SDag-Erling Smørgrav if (rs->rs_count <= len) 149*ff825849SDag-Erling Smørgrav rs->rs_count = 0; 150*ff825849SDag-Erling Smørgrav else 151*ff825849SDag-Erling Smørgrav rs->rs_count -= len; 152*ff825849SDag-Erling Smørgrav } 153*ff825849SDag-Erling Smørgrav 154*ff825849SDag-Erling Smørgrav static inline void 155*ff825849SDag-Erling Smørgrav _rs_rekey(u_char *dat, size_t datlen) 156*ff825849SDag-Erling Smørgrav { 157*ff825849SDag-Erling Smørgrav #ifndef KEYSTREAM_ONLY 158*ff825849SDag-Erling Smørgrav memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); 159*ff825849SDag-Erling Smørgrav #endif 160*ff825849SDag-Erling Smørgrav /* fill rs_buf with the keystream */ 161*ff825849SDag-Erling Smørgrav chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf, 162*ff825849SDag-Erling Smørgrav rsx->rs_buf, sizeof(rsx->rs_buf)); 163*ff825849SDag-Erling Smørgrav /* mix in optional user provided data */ 164*ff825849SDag-Erling Smørgrav if (dat) { 165*ff825849SDag-Erling Smørgrav size_t i, m; 166*ff825849SDag-Erling Smørgrav 167*ff825849SDag-Erling Smørgrav m = arc4_min(datlen, KEYSZ + IVSZ); 168*ff825849SDag-Erling Smørgrav for (i = 0; i < m; i++) 169*ff825849SDag-Erling Smørgrav rsx->rs_buf[i] ^= dat[i]; 170*ff825849SDag-Erling Smørgrav } 171*ff825849SDag-Erling Smørgrav /* immediately reinit for backtracking resistance */ 172*ff825849SDag-Erling Smørgrav _rs_init(rsx->rs_buf, KEYSZ + IVSZ); 173*ff825849SDag-Erling Smørgrav memset(rsx->rs_buf, 0, KEYSZ + IVSZ); 174*ff825849SDag-Erling Smørgrav rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ; 175*ff825849SDag-Erling Smørgrav } 176*ff825849SDag-Erling Smørgrav 177*ff825849SDag-Erling Smørgrav static inline void 178*ff825849SDag-Erling Smørgrav _rs_random_buf(void *_buf, size_t n) 179*ff825849SDag-Erling Smørgrav { 180*ff825849SDag-Erling Smørgrav u_char *buf = (u_char *)_buf; 181*ff825849SDag-Erling Smørgrav u_char *keystream; 182*ff825849SDag-Erling Smørgrav size_t m; 183*ff825849SDag-Erling Smørgrav 184*ff825849SDag-Erling Smørgrav _rs_stir_if_needed(n); 185*ff825849SDag-Erling Smørgrav while (n > 0) { 186*ff825849SDag-Erling Smørgrav if (rs->rs_have > 0) { 187*ff825849SDag-Erling Smørgrav m = arc4_min(n, rs->rs_have); 188*ff825849SDag-Erling Smørgrav keystream = rsx->rs_buf + sizeof(rsx->rs_buf) 189*ff825849SDag-Erling Smørgrav - rs->rs_have; 190*ff825849SDag-Erling Smørgrav memcpy(buf, keystream, m); 191*ff825849SDag-Erling Smørgrav memset(keystream, 0, m); 192*ff825849SDag-Erling Smørgrav buf += m; 193*ff825849SDag-Erling Smørgrav n -= m; 194*ff825849SDag-Erling Smørgrav rs->rs_have -= m; 195*ff825849SDag-Erling Smørgrav } 196*ff825849SDag-Erling Smørgrav if (rs->rs_have == 0) 197*ff825849SDag-Erling Smørgrav _rs_rekey(NULL, 0); 198*ff825849SDag-Erling Smørgrav } 199*ff825849SDag-Erling Smørgrav } 200*ff825849SDag-Erling Smørgrav 201*ff825849SDag-Erling Smørgrav static inline void 202*ff825849SDag-Erling Smørgrav _rs_random_u32(uint32_t *val) 203*ff825849SDag-Erling Smørgrav { 204*ff825849SDag-Erling Smørgrav u_char *keystream; 205*ff825849SDag-Erling Smørgrav _rs_stir_if_needed(sizeof(*val)); 206*ff825849SDag-Erling Smørgrav if (rs->rs_have < sizeof(*val)) 207*ff825849SDag-Erling Smørgrav _rs_rekey(NULL, 0); 208*ff825849SDag-Erling Smørgrav keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have; 209*ff825849SDag-Erling Smørgrav memcpy(val, keystream, sizeof(*val)); 210*ff825849SDag-Erling Smørgrav memset(keystream, 0, sizeof(*val)); 211*ff825849SDag-Erling Smørgrav rs->rs_have -= sizeof(*val); 212*ff825849SDag-Erling Smørgrav } 213*ff825849SDag-Erling Smørgrav 214*ff825849SDag-Erling Smørgrav uint32_t 215*ff825849SDag-Erling Smørgrav arc4random(void) 216*ff825849SDag-Erling Smørgrav { 217*ff825849SDag-Erling Smørgrav uint32_t val; 218*ff825849SDag-Erling Smørgrav 219*ff825849SDag-Erling Smørgrav _ARC4_LOCK(); 220*ff825849SDag-Erling Smørgrav _rs_random_u32(&val); 221*ff825849SDag-Erling Smørgrav _ARC4_UNLOCK(); 222*ff825849SDag-Erling Smørgrav return val; 223*ff825849SDag-Erling Smørgrav } 224*ff825849SDag-Erling Smørgrav 225*ff825849SDag-Erling Smørgrav void 226*ff825849SDag-Erling Smørgrav arc4random_buf(void *buf, size_t n) 227*ff825849SDag-Erling Smørgrav { 228*ff825849SDag-Erling Smørgrav _ARC4_LOCK(); 229*ff825849SDag-Erling Smørgrav _rs_random_buf(buf, n); 230*ff825849SDag-Erling Smørgrav _ARC4_UNLOCK(); 231*ff825849SDag-Erling Smørgrav } 232