ipfw: Use netisr wrappers
[dragonfly.git] / sys / kern / subr_csprng.c
blob6f4ba284861f71091a512de0560da598a97be906
1 /*
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
9 * are met:
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.
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.
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 * 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.
48 #define MIN_POOL_SIZE (64 + SHA256_DIGEST_LENGTH)
50 /* Minimum reseed interval */
51 #define MIN_RESEED_INTERVAL hz/10
53 /* Lock macros */
54 #define POOL_LOCK_INIT(pool) \
55 spin_init(&(pool)->lock, "csprng_poollock")
57 #define POOL_LOCK(pool) \
58 spin_lock(&pool->lock)
60 #define POOL_TRYLOCK(pool) \
61 spin_trylock(&pool->lock)
63 #define POOL_UNLOCK(pool) \
64 spin_unlock(&pool->lock)
67 #define STATE_LOCK_INIT(state) \
68 spin_init(&state->lock, "csprng_statelock")
70 #define STATE_LOCK(state) \
71 spin_lock(&state->lock)
73 #define STATE_UNLOCK(state) \
74 spin_unlock(&state->lock)
76 #define STATE_SLEEP(state, wmesg, timo) \
77 ssleep(state, &state->lock, 0, wmesg, timo)
79 #define STATE_WAKEUP(state) \
80 wakeup(state)
82 static void csprng_reseed_callout(void *arg);
83 static int csprng_reseed(struct csprng_state *state);
85 static struct timeval csprng_reseed_interval = { 0, 100000 };
87 static
88 int
89 csprng_pool_init(struct csprng_pool *pool, uint8_t *buf, size_t len)
91 pool->bytes = 0;
92 SHA256_Init(&pool->hash_ctx);
94 if (len > 0)
95 SHA256_Update(&pool->hash_ctx, buf, len);
97 return 0;
101 csprng_init(struct csprng_state *state)
103 int i, r;
105 bzero(state->key, sizeof(state->key));
106 bzero(&state->cipher_ctx, sizeof(state->cipher_ctx));
107 bzero(state->src_pool_idx, sizeof(state->src_pool_idx));
108 bzero(&state->last_reseed, sizeof(state->last_reseed));
110 state->nonce = 0;
111 state->ctr = 0;
112 state->reseed_cnt = 0;
113 state->failed_reseeds = 0;
114 state->callout_based_reseed = 0;
116 STATE_LOCK_INIT(state);
118 for (i = 0; i < 32; i++) {
119 r = csprng_pool_init(&state->pool[i], NULL, 0);
120 if (r != 0)
121 break;
122 POOL_LOCK_INIT(&state->pool[i]);
125 return r;
129 csprng_init_reseed(struct csprng_state *state)
131 state->callout_based_reseed = 1;
133 callout_init_mp(&state->reseed_callout);
134 callout_reset(&state->reseed_callout, MIN_RESEED_INTERVAL,
135 csprng_reseed_callout, state);
137 return 0;
141 * XXX:
142 * Sources don't really a uniquely-allocated src id...
143 * another way we could do that is by simply using
144 * (uint8_t)__LINE__ as the source id... cheap & cheerful.
147 static
149 encrypt_bytes(struct csprng_state *state, uint8_t *out, uint8_t *in,
150 size_t bytes)
152 /* Update nonce whenever the counter is about to overflow */
153 if (chacha_check_counter(&state->cipher_ctx)) {
154 ++state->nonce;
155 chacha_ivsetup(&state->cipher_ctx,
156 (const uint8_t *)&state->nonce);
159 chacha_encrypt_bytes(&state->cipher_ctx, in, out, (uint32_t)bytes);
161 return 0;
165 * XXX: flags is currently unused, but could be used to know whether
166 * it's a /dev/random or /dev/urandom read, and make sure that
167 * enough entropy has been collected recently, etc.
170 csprng_get_random(struct csprng_state *state, uint8_t *out, int bytes,
171 int flags __unused)
173 int cnt;
174 int total_bytes = 0;
177 * XXX: can optimize a bit by digging into chacha_encrypt_bytes
178 * and removing the xor of the stream with the input - that
179 * way we don't have to xor the output (which we provide
180 * as input).
182 bzero(out, bytes);
184 STATE_LOCK(state);
186 again:
187 if (!state->callout_based_reseed &&
188 ratecheck(&state->last_reseed, &csprng_reseed_interval)) {
189 csprng_reseed(state);
193 * If no reseed has occurred yet, we can't possibly give out
194 * any random data.
195 * Sleep until entropy is added to the pools (or a callout-based
196 * reseed, if enabled, occurs).
198 if (state->reseed_cnt == 0) {
199 STATE_SLEEP(state, "csprngrsd", 0);
200 goto again;
203 while (bytes > 0) {
204 /* Limit amount of output without rekeying to 2^20 */
205 cnt = (bytes > (1 << 20)) ? (1 << 20) : bytes;
207 encrypt_bytes(state, out, out, cnt);
209 /* Update key and rekey cipher */
210 encrypt_bytes(state, state->key, state->key,
211 sizeof(state->key));
212 chacha_keysetup(&state->cipher_ctx, state->key,
213 8*sizeof(state->key));
215 out += cnt;
216 bytes -= cnt;
217 total_bytes += cnt;
220 STATE_UNLOCK(state);
222 return total_bytes;
225 static
227 csprng_reseed(struct csprng_state *state)
229 int i;
230 struct csprng_pool *pool;
231 SHA256_CTX hash_ctx;
232 uint8_t digest[SHA256_DIGEST_LENGTH];
235 * If there's not enough entropy in the first
236 * pool, don't reseed.
238 if (state->pool[0].bytes < MIN_POOL_SIZE) {
239 ++state->failed_reseeds;
240 return 1;
243 SHA256_Init(&hash_ctx);
246 * Update hash that will result in new key with the
247 * old key.
249 SHA256_Update(&hash_ctx, state->key, sizeof(state->key));
251 state->reseed_cnt++;
253 for (i = 0; i < 32; i++) {
254 if ((state->reseed_cnt % (1 << i)) != 0)
255 break;
257 pool = &state->pool[i];
258 POOL_LOCK(pool);
261 * Finalize hash of the entropy in this pool.
263 SHA256_Final(digest, &pool->hash_ctx);
266 * Reinitialize pool with a hash of the old pool digest.
267 * This is a slight deviation from Fortuna as per reference,
268 * but is in line with other Fortuna implementations.
270 csprng_pool_init(pool, digest, sizeof(digest));
272 POOL_UNLOCK(pool);
275 * Update hash that will result in new key with this
276 * pool's hashed entropy.
278 SHA256_Update(&hash_ctx, digest, sizeof(digest));
281 SHA256_Final(state->key, &hash_ctx);
283 /* Update key and rekey cipher */
284 chacha_keysetup(&state->cipher_ctx, state->key,
285 8*sizeof(state->key));
287 /* Increment the nonce if the counter overflows */
288 if (chacha_incr_counter(&state->cipher_ctx)) {
289 ++state->nonce;
290 chacha_ivsetup(&state->cipher_ctx,
291 (const uint8_t *)&state->nonce);
294 return 0;
297 static
298 void
299 csprng_reseed_callout(void *arg)
301 struct csprng_state *state = (struct csprng_state *)arg;
302 int reseed_interval = MIN_RESEED_INTERVAL;
304 STATE_LOCK(state);
306 csprng_reseed(arg);
308 STATE_WAKEUP(state);
309 STATE_UNLOCK(state);
311 callout_reset(&state->reseed_callout, reseed_interval,
312 csprng_reseed_callout, state);
316 csprng_add_entropy(struct csprng_state *state, int src_id,
317 const uint8_t *entropy, size_t bytes, int flags)
319 struct csprng_pool *pool;
320 int pool_id;
323 * Pick the next pool for this source on a round-robin
324 * basis.
326 src_id &= 0xff;
327 pool_id = state->src_pool_idx[src_id]++ & 0x1f;
328 pool = &state->pool[pool_id];
330 if (flags & CSPRNG_TRYLOCK) {
332 * If we are asked to just try the lock instead
333 * of spinning until we get it, return if we
334 * can't get a hold of the lock right now.
336 if (!POOL_TRYLOCK(pool))
337 return -1;
338 } else {
339 POOL_LOCK(pool);
342 SHA256_Update(&pool->hash_ctx, (const uint8_t *)&src_id,
343 sizeof(src_id));
344 SHA256_Update(&pool->hash_ctx, (const uint8_t *)&bytes,
345 sizeof(bytes));
346 SHA256_Update(&pool->hash_ctx, entropy, bytes);
348 pool->bytes += bytes;
350 POOL_UNLOCK(pool);
353 * If a wakeup is missed, it doesn't matter too much - it'll get
354 * woken up by the next add_entropy() call.
356 STATE_WAKEUP(state);
358 return 0;