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 #define CHACHA_EMBED 42 #define CHACHA_NONCE0_CTR128 43 #define KEYSTREAM_ONLY 44 #include <crypto/chacha20/chacha.c> 45 #include <crypto/sha2/sha2.h> 46 47 /* 48 * Minimum amount of bytes in pool before we consider it 49 * good enough. 50 * It's 64 + the hash digest size because we always 51 * reinitialize the pools with a hash of the previous chunk 52 * of entropy. 53 */ 54 #define MIN_POOL_SIZE (64 + SHA256_DIGEST_LENGTH) 55 56 /* Minimum reseed interval */ 57 #define MIN_RESEED_INTERVAL hz/10 58 59 #if 0 60 static void csprng_reseed_callout(void *arg); 61 #endif 62 static int csprng_reseed(struct csprng_state *state); 63 64 static struct timeval csprng_reseed_interval = { 0, 100000 }; 65 66 static 67 int 68 csprng_pool_init(struct csprng_pool *pool, uint8_t *buf, size_t len) 69 { 70 pool->bytes = 0; 71 SHA256_Init(&pool->hash_ctx); 72 73 if (len > 0) 74 SHA256_Update(&pool->hash_ctx, buf, len); 75 76 return 0; 77 } 78 79 int 80 csprng_init(struct csprng_state *state) 81 { 82 int i, r; 83 84 bzero(state->key, sizeof(state->key)); 85 bzero(&state->cipher_ctx, sizeof(state->cipher_ctx)); 86 bzero(state->src_pool_idx, sizeof(state->src_pool_idx)); 87 bzero(&state->last_reseed, sizeof(state->last_reseed)); 88 89 state->reseed_cnt = 0; 90 state->failed_reseeds = 0; 91 state->callout_based_reseed = 0; 92 93 for (i = 0; i < 32; i++) { 94 r = csprng_pool_init(&state->pool[i], NULL, 0); 95 if (r != 0) 96 break; 97 } 98 99 return r; 100 } 101 102 #if 0 103 int 104 csprng_init_reseed(struct csprng_state *state) 105 { 106 state->callout_based_reseed = 1; 107 108 callout_init_mp(&state->reseed_callout); 109 callout_reset(&state->reseed_callout, MIN_RESEED_INTERVAL, 110 csprng_reseed_callout, state); 111 112 return 0; 113 } 114 #endif 115 116 /* 117 * XXX: 118 * Sources don't really a uniquely-allocated src id... 119 * another way we could do that is by simply using 120 * (uint8_t)__LINE__ as the source id... cheap & cheerful. 121 */ 122 123 /* 124 * Called with state->spin held. 125 */ 126 int 127 csprng_get_random(struct csprng_state *state, uint8_t *out, int bytes, 128 int flags) 129 { 130 int cnt; 131 int total_bytes = 0; 132 133 again: 134 if (!state->callout_based_reseed && 135 ratecheck(&state->last_reseed, &csprng_reseed_interval)) { 136 csprng_reseed(state); 137 } 138 139 /* 140 * If no reseed has occurred yet, we can't possibly give out 141 * any random data. 142 * If this isn't an unlimited (i.e., /dev/urandom) read, sleep 143 * until entropy is added to the pools (or a callout-based 144 * reseed, if enabled, occurs). 145 */ 146 if ((flags & CSPRNG_UNLIMITED) == 0 && state->reseed_cnt == 0) { 147 ssleep(state, &state->spin, 0, "csprngrsd", 0); 148 goto again; 149 } 150 151 while (bytes > 0) { 152 /* Limit amount of output without rekeying to 2^20 */ 153 cnt = (bytes > (1 << 20)) ? (1 << 20) : bytes; 154 155 chacha_encrypt_bytes(&state->cipher_ctx, NULL, out, cnt); 156 157 /* Update key and rekey cipher */ 158 chacha_encrypt_bytes(&state->cipher_ctx, NULL, state->key, 159 sizeof(state->key)); 160 chacha_keysetup(&state->cipher_ctx, state->key, 161 8 * sizeof(state->key)); 162 163 out += cnt; 164 bytes -= cnt; 165 total_bytes += cnt; 166 } 167 168 return total_bytes; 169 } 170 171 /* 172 * Called with state->spin held. 173 */ 174 static 175 int 176 csprng_reseed(struct csprng_state *state) 177 { 178 int i; 179 struct csprng_pool *pool; 180 SHA256_CTX hash_ctx; 181 uint8_t digest[SHA256_DIGEST_LENGTH]; 182 uint8_t counter[16]; 183 184 /* 185 * If there's not enough entropy in the first 186 * pool, don't reseed. 187 */ 188 if (state->pool[0].bytes < MIN_POOL_SIZE) { 189 ++state->failed_reseeds; 190 return 1; 191 } 192 193 SHA256_Init(&hash_ctx); 194 195 /* 196 * Update hash that will result in new key with the 197 * old key. 198 */ 199 SHA256_Update(&hash_ctx, state->key, sizeof(state->key)); 200 201 state->reseed_cnt++; 202 203 for (i = 0; i < 32; i++) { 204 if ((state->reseed_cnt % (1 << i)) != 0) 205 break; 206 207 pool = &state->pool[i]; 208 209 /* 210 * Finalize hash of the entropy in this pool. 211 */ 212 SHA256_Final(digest, &pool->hash_ctx); 213 214 /* 215 * Reinitialize pool with a hash of the old pool digest. 216 * This is a slight deviation from Fortuna as per reference, 217 * but is in line with other Fortuna implementations. 218 */ 219 csprng_pool_init(pool, digest, sizeof(digest)); 220 221 /* 222 * Update hash that will result in new key with this 223 * pool's hashed entropy. 224 */ 225 SHA256_Update(&hash_ctx, digest, sizeof(digest)); 226 } 227 228 SHA256_Final(state->key, &hash_ctx); 229 230 /* Update key and rekey cipher */ 231 chacha_keysetup(&state->cipher_ctx, state->key, 8*sizeof(state->key)); 232 233 /* No IV but a 128-bit counter, should never overflow */ 234 bzero(counter, sizeof(counter)); 235 chacha_ivsetup(&state->cipher_ctx, NULL, counter); 236 237 return 0; 238 } 239 240 #if 0 241 static 242 void 243 csprng_reseed_callout(void *arg) 244 { 245 struct csprng_state *state = (struct csprng_state *)arg; 246 int reseed_interval = MIN_RESEED_INTERVAL; 247 248 spin_lock(&state->spin); 249 csprng_reseed(arg); 250 spin_unlock(&state->spin); 251 wakeup(state); 252 253 callout_reset(&state->reseed_callout, reseed_interval, 254 csprng_reseed_callout, state); 255 } 256 #endif 257 258 /* 259 * Called with state->spin held 260 */ 261 int 262 csprng_add_entropy(struct csprng_state *state, int src_id, 263 const uint8_t *entropy, size_t bytes, int flags) 264 { 265 struct csprng_pool *pool; 266 int pool_id; 267 268 /* 269 * Pick the next pool for this source on a round-robin 270 * basis. 271 */ 272 src_id &= 0xff; 273 pool_id = state->src_pool_idx[src_id]++ & 0x1f; 274 pool = &state->pool[pool_id]; 275 276 SHA256_Update(&pool->hash_ctx, (const uint8_t *)&src_id, 277 sizeof(src_id)); 278 SHA256_Update(&pool->hash_ctx, (const uint8_t *)&bytes, 279 sizeof(bytes)); 280 SHA256_Update(&pool->hash_ctx, entropy, bytes); 281 282 pool->bytes += bytes; 283 284 return 0; 285 } 286