1 /* 2 * Copyright (c) 1996, David Mazieres <dm@uun.org> 3 * Copyright (c) 2008, Damien Miller <djm@openbsd.org> 4 * Copyright (c) 2013, Markus Friedl <markus@openbsd.org> 5 * Copyright (c) 2015 Joyent, Inc. 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* 21 * arc4random(3C), derived from the OpenBSD version. 22 * 23 * To ensure that a parent process and any potential children see a different 24 * state, we mmap the entire arc4_state_t structure and mark that page as 25 * MC_INHERIT_ZERO. That ensures that the data is zeroed, and really the bit we 26 * care about, arc4_init is set to B_FALSE, which will cause the child to 27 * reinitialize it when they first use the interface. 28 */ 29 30 #include <synch.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <unistd.h> 34 #include <sys/sysmacros.h> 35 #include <chacha.h> 36 37 #include "thr_uberdata.h" 38 39 #define ARC4_KEYSZ 32 40 #define ARC4_IVSZ 8 41 #define ARC4_BLOCKSZ 64 42 #define ARC4_KSBUFSZ (16*ARC4_BLOCKSZ) /* key stream byte size */ 43 #define ARC4_COUNT 1600000 /* bytes for rekeying */ 44 45 typedef struct arc4_state { 46 boolean_t arc4_init; /* Initialized? */ 47 size_t arc4_have; /* Valid bytes in arc4_buf */ 48 size_t arc4_count; /* bytes until reseed */ 49 chacha_ctx_t arc4_chacha; /* chacha context */ 50 uint8_t arc4_buf[ARC4_KSBUFSZ]; /* keystream blocks */ 51 } arc4_state_t; 52 53 static arc4_state_t *arc4; 54 static mutex_t arc4_lock = DEFAULTMUTEX; 55 56 static void 57 arc4_init(uint8_t *buf, size_t n) 58 { 59 if (n < ARC4_KEYSZ + ARC4_IVSZ) 60 abort(); 61 62 chacha_keysetup(&arc4->arc4_chacha, buf, ARC4_KEYSZ * 8, 0); 63 chacha_ivsetup(&arc4->arc4_chacha, buf + ARC4_KEYSZ); 64 } 65 66 static void 67 arc4_rekey(uint8_t *data, size_t datalen) 68 { 69 /* Fill in the keystream buffer */ 70 chacha_encrypt_bytes(&arc4->arc4_chacha, arc4->arc4_buf, arc4->arc4_buf, 71 sizeof (arc4->arc4_buf)); 72 73 /* mix in optional user provided data */ 74 if (data != NULL) { 75 size_t i, m; 76 77 m = MIN(datalen, ARC4_KEYSZ + ARC4_IVSZ); 78 for (i = 0; i < m; i++) 79 arc4->arc4_buf[i] ^= data[i]; 80 } 81 82 /* immediately reinit for backtracking resistence */ 83 arc4_init(arc4->arc4_buf, ARC4_KEYSZ + ARC4_IVSZ); 84 explicit_bzero(arc4->arc4_buf, ARC4_KEYSZ + ARC4_IVSZ); 85 arc4->arc4_have = sizeof (arc4->arc4_buf) - ARC4_KEYSZ - ARC4_IVSZ; 86 } 87 88 static void 89 arc4_stir(size_t len) 90 { 91 uint8_t rnd[ARC4_KEYSZ + ARC4_IVSZ]; 92 93 if (arc4->arc4_count <= len) { 94 if (getentropy(rnd, sizeof (rnd)) == -1) 95 abort(); 96 97 if (arc4->arc4_init == B_FALSE) { 98 arc4_init(rnd, sizeof (rnd)); 99 arc4->arc4_init = B_TRUE; 100 } else { 101 arc4_rekey(rnd, sizeof (rnd)); 102 } 103 explicit_bzero(rnd, sizeof (rnd)); 104 105 /* Invalidate the data buffer */ 106 arc4->arc4_have = 0; 107 memset(arc4->arc4_buf, 0, sizeof (arc4->arc4_buf)); 108 arc4->arc4_count = ARC4_COUNT; 109 } 110 111 if (arc4->arc4_count <= len) { 112 arc4->arc4_count = 0; 113 } else { 114 arc4->arc4_count -= len; 115 } 116 } 117 118 static void 119 arc4_fill(uint8_t *buf, size_t n) 120 { 121 if (arc4 == NULL) { 122 size_t pgsz, mapsz; 123 void *a; 124 125 pgsz = sysconf(_SC_PAGESIZE); 126 if (pgsz == -1) 127 abort(); 128 mapsz = P2ROUNDUP(sizeof (arc4_state_t), pgsz); 129 a = mmap(NULL, mapsz, PROT_READ | PROT_WRITE, 130 MAP_PRIVATE | MAP_ANON, -1, 0); 131 if (a == MAP_FAILED) 132 abort(); 133 if (memcntl(a, mapsz, MC_INHERIT_ZERO, 0, 0, 0) != 0) 134 abort(); 135 arc4 = a; 136 } 137 138 arc4_stir(n); 139 while (n > 0) { 140 if (arc4->arc4_have > 0) { 141 uint8_t *keystream; 142 size_t m = MIN(n, arc4->arc4_have); 143 144 keystream = arc4->arc4_buf + sizeof (arc4->arc4_buf) - 145 arc4->arc4_have; 146 memcpy(buf, keystream, m); 147 explicit_bzero(keystream, m); 148 buf += m; 149 n -= m; 150 arc4->arc4_have -= m; 151 } 152 if (arc4->arc4_have == 0) 153 arc4_rekey(NULL, 0); 154 } 155 } 156 157 uint32_t 158 arc4random(void) 159 { 160 uint32_t out; 161 162 lmutex_lock(&arc4_lock); 163 arc4_fill((uint8_t *)&out, sizeof (uint32_t)); 164 lmutex_unlock(&arc4_lock); 165 return (out); 166 } 167 168 void 169 arc4random_buf(void *buf, size_t n) 170 { 171 lmutex_lock(&arc4_lock); 172 arc4_fill(buf, n); 173 lmutex_unlock(&arc4_lock); 174 } 175