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__ */ 51b5663de9SDag-Erling Smørgrav #ifndef MAP_ANON 52b5663de9SDag-Erling Smørgrav #define MAP_ANON MAP_ANONYMOUS 53b5663de9SDag-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 743bd4df0aSDag-Erling Smørgrav /* 753bd4df0aSDag-Erling Smørgrav * Basic sanity checking; wish we could do better. 763bd4df0aSDag-Erling Smørgrav */ 773bd4df0aSDag-Erling Smørgrav static int 783bd4df0aSDag-Erling Smørgrav fallback_gotdata(char *buf, size_t len) 793bd4df0aSDag-Erling Smørgrav { 803bd4df0aSDag-Erling Smørgrav char any_set = 0; 813bd4df0aSDag-Erling Smørgrav size_t i; 823bd4df0aSDag-Erling Smørgrav 833bd4df0aSDag-Erling Smørgrav for (i = 0; i < len; ++i) 843bd4df0aSDag-Erling Smørgrav any_set |= buf[i]; 853bd4df0aSDag-Erling Smørgrav if (any_set == 0) 863bd4df0aSDag-Erling Smørgrav return -1; 873bd4df0aSDag-Erling Smørgrav return 0; 883bd4df0aSDag-Erling Smørgrav } 893bd4df0aSDag-Erling Smørgrav 903bd4df0aSDag-Erling Smørgrav /* fallback for getentropy in case libc returns failure */ 913bd4df0aSDag-Erling Smørgrav static int 923bd4df0aSDag-Erling Smørgrav fallback_getentropy_urandom(void *buf, size_t len) 933bd4df0aSDag-Erling Smørgrav { 943bd4df0aSDag-Erling Smørgrav size_t i; 953bd4df0aSDag-Erling Smørgrav int fd, flags; 963bd4df0aSDag-Erling Smørgrav int save_errno = errno; 973bd4df0aSDag-Erling Smørgrav 983bd4df0aSDag-Erling Smørgrav start: 993bd4df0aSDag-Erling Smørgrav 1003bd4df0aSDag-Erling Smørgrav flags = O_RDONLY; 1013bd4df0aSDag-Erling Smørgrav #ifdef O_NOFOLLOW 1023bd4df0aSDag-Erling Smørgrav flags |= O_NOFOLLOW; 1033bd4df0aSDag-Erling Smørgrav #endif 1043bd4df0aSDag-Erling Smørgrav #ifdef O_CLOEXEC 1053bd4df0aSDag-Erling Smørgrav flags |= O_CLOEXEC; 1063bd4df0aSDag-Erling Smørgrav #endif 1073bd4df0aSDag-Erling Smørgrav fd = open("/dev/urandom", flags, 0); 1083bd4df0aSDag-Erling Smørgrav if (fd == -1) { 1093bd4df0aSDag-Erling Smørgrav if (errno == EINTR) 1103bd4df0aSDag-Erling Smørgrav goto start; 1113bd4df0aSDag-Erling Smørgrav goto nodevrandom; 1123bd4df0aSDag-Erling Smørgrav } 1133bd4df0aSDag-Erling Smørgrav #ifndef O_CLOEXEC 1143bd4df0aSDag-Erling Smørgrav # ifdef HAVE_FCNTL 1153bd4df0aSDag-Erling Smørgrav fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); 1163bd4df0aSDag-Erling Smørgrav # endif 1173bd4df0aSDag-Erling Smørgrav #endif 1183bd4df0aSDag-Erling Smørgrav for (i = 0; i < len; ) { 1193bd4df0aSDag-Erling Smørgrav size_t wanted = len - i; 1203bd4df0aSDag-Erling Smørgrav ssize_t ret = read(fd, (char*)buf + i, wanted); 1213bd4df0aSDag-Erling Smørgrav 1223bd4df0aSDag-Erling Smørgrav if (ret == -1) { 1233bd4df0aSDag-Erling Smørgrav if (errno == EAGAIN || errno == EINTR) 1243bd4df0aSDag-Erling Smørgrav continue; 1253bd4df0aSDag-Erling Smørgrav close(fd); 1263bd4df0aSDag-Erling Smørgrav goto nodevrandom; 1273bd4df0aSDag-Erling Smørgrav } 1283bd4df0aSDag-Erling Smørgrav i += ret; 1293bd4df0aSDag-Erling Smørgrav } 1303bd4df0aSDag-Erling Smørgrav close(fd); 1313bd4df0aSDag-Erling Smørgrav if (fallback_gotdata(buf, len) == 0) { 1323bd4df0aSDag-Erling Smørgrav errno = save_errno; 1333bd4df0aSDag-Erling Smørgrav return 0; /* satisfied */ 1343bd4df0aSDag-Erling Smørgrav } 1353bd4df0aSDag-Erling Smørgrav nodevrandom: 1363bd4df0aSDag-Erling Smørgrav errno = EIO; 1373bd4df0aSDag-Erling Smørgrav return -1; 1383bd4df0aSDag-Erling Smørgrav } 1393bd4df0aSDag-Erling Smørgrav 140ff825849SDag-Erling Smørgrav static inline void 141ff825849SDag-Erling Smørgrav _rs_init(u_char *buf, size_t n) 142ff825849SDag-Erling Smørgrav { 143*e86b9096SDag-Erling Smørgrav assert(buf); 144ff825849SDag-Erling Smørgrav if (n < KEYSZ + IVSZ) 145ff825849SDag-Erling Smørgrav return; 146ff825849SDag-Erling Smørgrav 147ff825849SDag-Erling Smørgrav if (rs == NULL) { 148ff825849SDag-Erling Smørgrav #ifndef UB_ON_WINDOWS 149ff825849SDag-Erling Smørgrav if ((rs = mmap(NULL, sizeof(*rs), PROT_READ|PROT_WRITE, 150ff825849SDag-Erling Smørgrav MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) 151ff825849SDag-Erling Smørgrav abort(); 152ff825849SDag-Erling Smørgrav #ifdef MAP_INHERIT_ZERO 153ff825849SDag-Erling Smørgrav if (minherit(rs, sizeof(*rs), MAP_INHERIT_ZERO) == -1) 154ff825849SDag-Erling Smørgrav abort(); 155ff825849SDag-Erling Smørgrav #endif 156ff825849SDag-Erling Smørgrav #else /* WINDOWS */ 157ff825849SDag-Erling Smørgrav rs = malloc(sizeof(*rs)); 158ff825849SDag-Erling Smørgrav if(!rs) 159ff825849SDag-Erling Smørgrav abort(); 160ff825849SDag-Erling Smørgrav #endif 161ff825849SDag-Erling Smørgrav } 162ff825849SDag-Erling Smørgrav if (rsx == NULL) { 163ff825849SDag-Erling Smørgrav #ifndef UB_ON_WINDOWS 164ff825849SDag-Erling Smørgrav if ((rsx = mmap(NULL, sizeof(*rsx), PROT_READ|PROT_WRITE, 165ff825849SDag-Erling Smørgrav MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) 166ff825849SDag-Erling Smørgrav abort(); 167ff825849SDag-Erling Smørgrav #else /* WINDOWS */ 168ff825849SDag-Erling Smørgrav rsx = malloc(sizeof(*rsx)); 169ff825849SDag-Erling Smørgrav if(!rsx) 170ff825849SDag-Erling Smørgrav abort(); 171ff825849SDag-Erling Smørgrav #endif 172ff825849SDag-Erling Smørgrav } 173ff825849SDag-Erling Smørgrav 174ff825849SDag-Erling Smørgrav chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8, 0); 175ff825849SDag-Erling Smørgrav chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ); 176ff825849SDag-Erling Smørgrav } 177ff825849SDag-Erling Smørgrav 178ff825849SDag-Erling Smørgrav static void 179ff825849SDag-Erling Smørgrav _rs_stir(void) 180ff825849SDag-Erling Smørgrav { 181ff825849SDag-Erling Smørgrav u_char rnd[KEYSZ + IVSZ]; 182ff825849SDag-Erling Smørgrav 183ff825849SDag-Erling Smørgrav if (getentropy(rnd, sizeof rnd) == -1) { 1843bd4df0aSDag-Erling Smørgrav if(errno != ENOSYS || 1853bd4df0aSDag-Erling Smørgrav fallback_getentropy_urandom(rnd, sizeof rnd) == -1) { 186ff825849SDag-Erling Smørgrav #ifdef SIGKILL 187ff825849SDag-Erling Smørgrav raise(SIGKILL); 188ff825849SDag-Erling Smørgrav #else 189ff825849SDag-Erling Smørgrav exit(9); /* windows */ 190ff825849SDag-Erling Smørgrav #endif 191ff825849SDag-Erling Smørgrav } 1923bd4df0aSDag-Erling Smørgrav } 193ff825849SDag-Erling Smørgrav 194ff825849SDag-Erling Smørgrav if (!rs) 195ff825849SDag-Erling Smørgrav _rs_init(rnd, sizeof(rnd)); 196ff825849SDag-Erling Smørgrav else 197ff825849SDag-Erling Smørgrav _rs_rekey(rnd, sizeof(rnd)); 198ff825849SDag-Erling Smørgrav explicit_bzero(rnd, sizeof(rnd)); /* discard source seed */ 199ff825849SDag-Erling Smørgrav 200ff825849SDag-Erling Smørgrav /* invalidate rs_buf */ 201ff825849SDag-Erling Smørgrav rs->rs_have = 0; 202ff825849SDag-Erling Smørgrav memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); 203ff825849SDag-Erling Smørgrav 204ff825849SDag-Erling Smørgrav rs->rs_count = 1600000; 205ff825849SDag-Erling Smørgrav } 206ff825849SDag-Erling Smørgrav 207ff825849SDag-Erling Smørgrav static inline void 208ff825849SDag-Erling Smørgrav _rs_stir_if_needed(size_t len) 209ff825849SDag-Erling Smørgrav { 210ff825849SDag-Erling Smørgrav #ifndef MAP_INHERIT_ZERO 211ff825849SDag-Erling Smørgrav static pid_t _rs_pid = 0; 212ff825849SDag-Erling Smørgrav pid_t pid = getpid(); 213ff825849SDag-Erling Smørgrav 214ff825849SDag-Erling Smørgrav /* If a system lacks MAP_INHERIT_ZERO, resort to getpid() */ 215ff825849SDag-Erling Smørgrav if (_rs_pid == 0 || _rs_pid != pid) { 216ff825849SDag-Erling Smørgrav _rs_pid = pid; 217ff825849SDag-Erling Smørgrav if (rs) 218ff825849SDag-Erling Smørgrav rs->rs_count = 0; 219ff825849SDag-Erling Smørgrav } 220ff825849SDag-Erling Smørgrav #endif 221ff825849SDag-Erling Smørgrav if (!rs || rs->rs_count <= len) 222ff825849SDag-Erling Smørgrav _rs_stir(); 223ff825849SDag-Erling Smørgrav if (rs->rs_count <= len) 224ff825849SDag-Erling Smørgrav rs->rs_count = 0; 225ff825849SDag-Erling Smørgrav else 226ff825849SDag-Erling Smørgrav rs->rs_count -= len; 227ff825849SDag-Erling Smørgrav } 228ff825849SDag-Erling Smørgrav 229ff825849SDag-Erling Smørgrav static inline void 230ff825849SDag-Erling Smørgrav _rs_rekey(u_char *dat, size_t datlen) 231ff825849SDag-Erling Smørgrav { 232ff825849SDag-Erling Smørgrav #ifndef KEYSTREAM_ONLY 233ff825849SDag-Erling Smørgrav memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); 234ff825849SDag-Erling Smørgrav #endif 235ff825849SDag-Erling Smørgrav /* fill rs_buf with the keystream */ 236ff825849SDag-Erling Smørgrav chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf, 237ff825849SDag-Erling Smørgrav rsx->rs_buf, sizeof(rsx->rs_buf)); 238ff825849SDag-Erling Smørgrav /* mix in optional user provided data */ 239ff825849SDag-Erling Smørgrav if (dat) { 240ff825849SDag-Erling Smørgrav size_t i, m; 241ff825849SDag-Erling Smørgrav 242ff825849SDag-Erling Smørgrav m = arc4_min(datlen, KEYSZ + IVSZ); 243ff825849SDag-Erling Smørgrav for (i = 0; i < m; i++) 244ff825849SDag-Erling Smørgrav rsx->rs_buf[i] ^= dat[i]; 245ff825849SDag-Erling Smørgrav } 246ff825849SDag-Erling Smørgrav /* immediately reinit for backtracking resistance */ 247ff825849SDag-Erling Smørgrav _rs_init(rsx->rs_buf, KEYSZ + IVSZ); 248ff825849SDag-Erling Smørgrav memset(rsx->rs_buf, 0, KEYSZ + IVSZ); 249ff825849SDag-Erling Smørgrav rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ; 250ff825849SDag-Erling Smørgrav } 251ff825849SDag-Erling Smørgrav 252ff825849SDag-Erling Smørgrav static inline void 253ff825849SDag-Erling Smørgrav _rs_random_buf(void *_buf, size_t n) 254ff825849SDag-Erling Smørgrav { 255ff825849SDag-Erling Smørgrav u_char *buf = (u_char *)_buf; 256ff825849SDag-Erling Smørgrav u_char *keystream; 257ff825849SDag-Erling Smørgrav size_t m; 258ff825849SDag-Erling Smørgrav 259ff825849SDag-Erling Smørgrav _rs_stir_if_needed(n); 260ff825849SDag-Erling Smørgrav while (n > 0) { 261ff825849SDag-Erling Smørgrav if (rs->rs_have > 0) { 262ff825849SDag-Erling Smørgrav m = arc4_min(n, rs->rs_have); 263ff825849SDag-Erling Smørgrav keystream = rsx->rs_buf + sizeof(rsx->rs_buf) 264ff825849SDag-Erling Smørgrav - rs->rs_have; 265ff825849SDag-Erling Smørgrav memcpy(buf, keystream, m); 266ff825849SDag-Erling Smørgrav memset(keystream, 0, m); 267ff825849SDag-Erling Smørgrav buf += m; 268ff825849SDag-Erling Smørgrav n -= m; 269ff825849SDag-Erling Smørgrav rs->rs_have -= m; 270ff825849SDag-Erling Smørgrav } 271ff825849SDag-Erling Smørgrav if (rs->rs_have == 0) 272ff825849SDag-Erling Smørgrav _rs_rekey(NULL, 0); 273ff825849SDag-Erling Smørgrav } 274ff825849SDag-Erling Smørgrav } 275ff825849SDag-Erling Smørgrav 276ff825849SDag-Erling Smørgrav static inline void 277ff825849SDag-Erling Smørgrav _rs_random_u32(uint32_t *val) 278ff825849SDag-Erling Smørgrav { 279ff825849SDag-Erling Smørgrav u_char *keystream; 280ff825849SDag-Erling Smørgrav _rs_stir_if_needed(sizeof(*val)); 281ff825849SDag-Erling Smørgrav if (rs->rs_have < sizeof(*val)) 282ff825849SDag-Erling Smørgrav _rs_rekey(NULL, 0); 283ff825849SDag-Erling Smørgrav keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have; 284ff825849SDag-Erling Smørgrav memcpy(val, keystream, sizeof(*val)); 285ff825849SDag-Erling Smørgrav memset(keystream, 0, sizeof(*val)); 286ff825849SDag-Erling Smørgrav rs->rs_have -= sizeof(*val); 287ff825849SDag-Erling Smørgrav } 288ff825849SDag-Erling Smørgrav 289ff825849SDag-Erling Smørgrav uint32_t 290ff825849SDag-Erling Smørgrav arc4random(void) 291ff825849SDag-Erling Smørgrav { 292ff825849SDag-Erling Smørgrav uint32_t val; 293ff825849SDag-Erling Smørgrav 294ff825849SDag-Erling Smørgrav _ARC4_LOCK(); 295ff825849SDag-Erling Smørgrav _rs_random_u32(&val); 296ff825849SDag-Erling Smørgrav _ARC4_UNLOCK(); 297ff825849SDag-Erling Smørgrav return val; 298ff825849SDag-Erling Smørgrav } 299ff825849SDag-Erling Smørgrav 300ff825849SDag-Erling Smørgrav void 301ff825849SDag-Erling Smørgrav arc4random_buf(void *buf, size_t n) 302ff825849SDag-Erling Smørgrav { 303ff825849SDag-Erling Smørgrav _ARC4_LOCK(); 304ff825849SDag-Erling Smørgrav _rs_random_buf(buf, n); 305ff825849SDag-Erling Smørgrav _ARC4_UNLOCK(); 306ff825849SDag-Erling Smørgrav } 307