2 * Copyright (c) 2014 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Alex Hornung <alex@alexhornung.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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
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>
42 #define CHACHA_NONCE0_CTR128
43 #define KEYSTREAM_ONLY
44 #include <crypto/chacha20/chacha.c>
45 #include <crypto/sha2/sha2.h>
48 * Minimum amount of bytes in pool before we consider it
50 * It's 64 + the hash digest size because we always
51 * reinitialize the pools with a hash of the previous chunk
54 #define MIN_POOL_SIZE (64 + SHA256_DIGEST_LENGTH)
56 /* Minimum reseed interval */
57 #define MIN_RESEED_INTERVAL hz/10
60 static void csprng_reseed_callout(void *arg);
62 static int csprng_reseed(struct csprng_state *state);
64 static struct timeval csprng_reseed_interval = { 0, 100000 };
68 csprng_pool_init(struct csprng_pool *pool, uint8_t *buf, size_t len)
71 SHA256_Init(&pool->hash_ctx);
74 SHA256_Update(&pool->hash_ctx, buf, len);
80 csprng_init(struct csprng_state *state)
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));
89 state->reseed_cnt = 0;
90 state->failed_reseeds = 0;
91 state->callout_based_reseed = 0;
93 for (i = 0; i < 32; i++) {
94 r = csprng_pool_init(&state->pool[i], NULL, 0);
104 csprng_init_reseed(struct csprng_state *state)
106 state->callout_based_reseed = 1;
108 callout_init_mp(&state->reseed_callout);
109 callout_reset(&state->reseed_callout, MIN_RESEED_INTERVAL,
110 csprng_reseed_callout, state);
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.
124 * Called with state->spin held.
127 csprng_get_random(struct csprng_state *state, uint8_t *out, int bytes,
134 if (!state->callout_based_reseed &&
135 ratecheck(&state->last_reseed, &csprng_reseed_interval)) {
136 csprng_reseed(state);
140 * If no reseed has occurred yet, we can't possibly give out
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).
146 if ((flags & CSPRNG_UNLIMITED) == 0 && state->reseed_cnt == 0) {
147 ssleep(state, &state->spin, 0, "csprngrsd", 0);
152 /* Limit amount of output without rekeying to 2^20 */
153 cnt = (bytes > (1 << 20)) ? (1 << 20) : bytes;
155 chacha_encrypt_bytes(&state->cipher_ctx, NULL, out, cnt);
157 /* Update key and rekey cipher */
158 chacha_encrypt_bytes(&state->cipher_ctx, NULL, state->key,
160 chacha_keysetup(&state->cipher_ctx, state->key,
161 8 * sizeof(state->key));
172 * Called with state->spin held.
176 csprng_reseed(struct csprng_state *state)
179 struct csprng_pool *pool;
181 uint8_t digest[SHA256_DIGEST_LENGTH];
185 * If there's not enough entropy in the first
186 * pool, don't reseed.
188 if (state->pool[0].bytes < MIN_POOL_SIZE) {
189 ++state->failed_reseeds;
193 SHA256_Init(&hash_ctx);
196 * Update hash that will result in new key with the
199 SHA256_Update(&hash_ctx, state->key, sizeof(state->key));
203 for (i = 0; i < 32; i++) {
204 if ((state->reseed_cnt % (1 << i)) != 0)
207 pool = &state->pool[i];
210 * Finalize hash of the entropy in this pool.
212 SHA256_Final(digest, &pool->hash_ctx);
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.
219 csprng_pool_init(pool, digest, sizeof(digest));
222 * Update hash that will result in new key with this
223 * pool's hashed entropy.
225 SHA256_Update(&hash_ctx, digest, sizeof(digest));
228 SHA256_Final(state->key, &hash_ctx);
230 /* Update key and rekey cipher */
231 chacha_keysetup(&state->cipher_ctx, state->key, 8*sizeof(state->key));
233 /* No IV but a 128-bit counter, should never overflow */
234 bzero(counter, sizeof(counter));
235 chacha_ivsetup(&state->cipher_ctx, NULL, counter);
243 csprng_reseed_callout(void *arg)
245 struct csprng_state *state = (struct csprng_state *)arg;
246 int reseed_interval = MIN_RESEED_INTERVAL;
248 spin_lock(&state->spin);
250 spin_unlock(&state->spin);
253 callout_reset(&state->reseed_callout, reseed_interval,
254 csprng_reseed_callout, state);
259 * Called with state->spin held
262 csprng_add_entropy(struct csprng_state *state, int src_id,
263 const uint8_t *entropy, size_t bytes, int flags)
265 struct csprng_pool *pool;
269 * Pick the next pool for this source on a round-robin
273 pool_id = state->src_pool_idx[src_id]++ & 0x1f;
274 pool = &state->pool[pool_id];
276 SHA256_Update(&pool->hash_ctx, (const uint8_t *)&src_id,
278 SHA256_Update(&pool->hash_ctx, (const uint8_t *)&bytes,
280 SHA256_Update(&pool->hash_ctx, entropy, bytes);
282 pool->bytes += bytes;