1 /* 2 * Copyright (c) 2014 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Alex Hornung <alex@alexhornung.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/spinlock.h> 38 #include <sys/spinlock2.h> 39 #include <sys/csprng.h> 40 41 /* 42 * Minimum amount of bytes in pool before we consider it 43 * good enough. 44 * It's 64 + the hash digest size because we always 45 * reinitialize the pools with a hash of the previous chunk 46 * of entropy. 47 */ 48 #define MIN_POOL_SIZE (64 + SHA256_DIGEST_LENGTH) 49 50 /* Minimum reseed interval */ 51 #define MIN_RESEED_INTERVAL hz/10 52 53 #if 0 54 static void csprng_reseed_callout(void *arg); 55 #endif 56 static int csprng_reseed(struct csprng_state *state); 57 58 static struct timeval csprng_reseed_interval = { 0, 100000 }; 59 60 static 61 int 62 csprng_pool_init(struct csprng_pool *pool, uint8_t *buf, size_t len) 63 { 64 pool->bytes = 0; 65 SHA256_Init(&pool->hash_ctx); 66 67 if (len > 0) 68 SHA256_Update(&pool->hash_ctx, buf, len); 69 70 return 0; 71 } 72 73 int 74 csprng_init(struct csprng_state *state) 75 { 76 int i, r; 77 78 bzero(state->key, sizeof(state->key)); 79 bzero(&state->cipher_ctx, sizeof(state->cipher_ctx)); 80 bzero(state->src_pool_idx, sizeof(state->src_pool_idx)); 81 bzero(&state->last_reseed, sizeof(state->last_reseed)); 82 83 state->nonce = 0; 84 state->ctr = 0; 85 state->reseed_cnt = 0; 86 state->failed_reseeds = 0; 87 state->callout_based_reseed = 0; 88 89 for (i = 0; i < 32; i++) { 90 r = csprng_pool_init(&state->pool[i], NULL, 0); 91 if (r != 0) 92 break; 93 } 94 95 return r; 96 } 97 98 #if 0 99 int 100 csprng_init_reseed(struct csprng_state *state) 101 { 102 state->callout_based_reseed = 1; 103 104 callout_init_mp(&state->reseed_callout); 105 callout_reset(&state->reseed_callout, MIN_RESEED_INTERVAL, 106 csprng_reseed_callout, state); 107 108 return 0; 109 } 110 #endif 111 112 /* 113 * XXX: 114 * Sources don't really a uniquely-allocated src id... 115 * another way we could do that is by simply using 116 * (uint8_t)__LINE__ as the source id... cheap & cheerful. 117 */ 118 119 static 120 int 121 encrypt_bytes(struct csprng_state *state, uint8_t *out, uint8_t *in, 122 size_t bytes) 123 { 124 /* Update nonce whenever the counter is about to overflow */ 125 if (chacha_check_counter(&state->cipher_ctx)) { 126 ++state->nonce; 127 chacha_ivsetup(&state->cipher_ctx, 128 (const uint8_t *)&state->nonce); 129 } 130 131 chacha_encrypt_bytes(&state->cipher_ctx, in, out, (uint32_t)bytes); 132 133 return 0; 134 } 135 136 /* 137 * 138 * Called with state->spin held. 139 * 140 * XXX: flags is currently unused, but could be used to know whether 141 * it's a /dev/random or /dev/urandom read, and make sure that 142 * enough entropy has been collected recently, etc. 143 */ 144 int 145 csprng_get_random(struct csprng_state *state, uint8_t *out, int bytes, 146 int flags __unused, int unlimited) 147 { 148 int cnt; 149 int total_bytes = 0; 150 151 /* 152 * XXX: can optimize a bit by digging into chacha_encrypt_bytes 153 * and removing the xor of the stream with the input - that 154 * way we don't have to xor the output (which we provide 155 * as input). 156 */ 157 bzero(out, bytes); 158 159 again: 160 if (!state->callout_based_reseed && 161 ratecheck(&state->last_reseed, &csprng_reseed_interval)) { 162 csprng_reseed(state); 163 } 164 165 /* 166 * If no reseed has occurred yet, we can't possibly give out 167 * any random data. 168 * Sleep until entropy is added to the pools (or a callout-based 169 * reseed, if enabled, occurs). 170 */ 171 if (unlimited == 0 && state->reseed_cnt == 0) { 172 ssleep(state, &state->spin, 0, "csprngrsd", 0); 173 goto again; 174 } 175 176 while (bytes > 0) { 177 /* Limit amount of output without rekeying to 2^20 */ 178 cnt = (bytes > (1 << 20)) ? (1 << 20) : bytes; 179 180 encrypt_bytes(state, out, out, cnt); 181 182 /* Update key and rekey cipher */ 183 encrypt_bytes(state, state->key, state->key, 184 sizeof(state->key)); 185 chacha_keysetup(&state->cipher_ctx, state->key, 186 8*sizeof(state->key)); 187 188 out += cnt; 189 bytes -= cnt; 190 total_bytes += cnt; 191 } 192 193 return total_bytes; 194 } 195 196 /* 197 * Called with state->spin held. 198 */ 199 static 200 int 201 csprng_reseed(struct csprng_state *state) 202 { 203 int i; 204 struct csprng_pool *pool; 205 SHA256_CTX hash_ctx; 206 uint8_t digest[SHA256_DIGEST_LENGTH]; 207 208 /* 209 * If there's not enough entropy in the first 210 * pool, don't reseed. 211 */ 212 if (state->pool[0].bytes < MIN_POOL_SIZE) { 213 ++state->failed_reseeds; 214 return 1; 215 } 216 217 SHA256_Init(&hash_ctx); 218 219 /* 220 * Update hash that will result in new key with the 221 * old key. 222 */ 223 SHA256_Update(&hash_ctx, state->key, sizeof(state->key)); 224 225 state->reseed_cnt++; 226 227 for (i = 0; i < 32; i++) { 228 if ((state->reseed_cnt % (1 << i)) != 0) 229 break; 230 231 pool = &state->pool[i]; 232 233 /* 234 * Finalize hash of the entropy in this pool. 235 */ 236 SHA256_Final(digest, &pool->hash_ctx); 237 238 /* 239 * Reinitialize pool with a hash of the old pool digest. 240 * This is a slight deviation from Fortuna as per reference, 241 * but is in line with other Fortuna implementations. 242 */ 243 csprng_pool_init(pool, digest, sizeof(digest)); 244 245 /* 246 * Update hash that will result in new key with this 247 * pool's hashed entropy. 248 */ 249 SHA256_Update(&hash_ctx, digest, sizeof(digest)); 250 } 251 252 SHA256_Final(state->key, &hash_ctx); 253 254 /* Update key and rekey cipher */ 255 chacha_keysetup(&state->cipher_ctx, state->key, 256 8*sizeof(state->key)); 257 258 /* Increment the nonce if the counter overflows */ 259 if (chacha_incr_counter(&state->cipher_ctx)) { 260 ++state->nonce; 261 chacha_ivsetup(&state->cipher_ctx, 262 (const uint8_t *)&state->nonce); 263 } 264 265 return 0; 266 } 267 268 #if 0 269 static 270 void 271 csprng_reseed_callout(void *arg) 272 { 273 struct csprng_state *state = (struct csprng_state *)arg; 274 int reseed_interval = MIN_RESEED_INTERVAL; 275 276 spin_lock(&state->spin); 277 csprng_reseed(arg); 278 spin_unlock(&state->spin); 279 wakeup(state); 280 281 callout_reset(&state->reseed_callout, reseed_interval, 282 csprng_reseed_callout, state); 283 } 284 #endif 285 286 /* 287 * Called with state->spin held 288 */ 289 int 290 csprng_add_entropy(struct csprng_state *state, int src_id, 291 const uint8_t *entropy, size_t bytes, int flags) 292 { 293 struct csprng_pool *pool; 294 int pool_id; 295 296 /* 297 * Pick the next pool for this source on a round-robin 298 * basis. 299 */ 300 src_id &= 0xff; 301 pool_id = state->src_pool_idx[src_id]++ & 0x1f; 302 pool = &state->pool[pool_id]; 303 304 SHA256_Update(&pool->hash_ctx, (const uint8_t *)&src_id, 305 sizeof(src_id)); 306 SHA256_Update(&pool->hash_ctx, (const uint8_t *)&bytes, 307 sizeof(bytes)); 308 SHA256_Update(&pool->hash_ctx, entropy, bytes); 309 310 pool->bytes += bytes; 311 312 return 0; 313 } 314