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