sys/vfs/msdosfs: Sync with FreeBSD (non functional diffs)
[dragonfly.git] / sys / kern / subr_csprng.c
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 /* Lock macros */
54 #define POOL_LOCK_INIT(pool) \
55     spin_init(&(pool)->lock, "csprng_poollock")
56
57 #define POOL_LOCK(pool)      \
58     spin_lock(&pool->lock)
59
60 #define POOL_TRYLOCK(pool)   \
61     spin_trylock(&pool->lock)
62
63 #define POOL_UNLOCK(pool)    \
64     spin_unlock(&pool->lock)
65
66
67 #define STATE_LOCK_INIT(state)  \
68     spin_init(&state->lock, "csprng_statelock")
69
70 #define STATE_LOCK(state)       \
71     spin_lock(&state->lock)
72
73 #define STATE_UNLOCK(state)     \
74     spin_unlock(&state->lock)
75
76 #define STATE_SLEEP(state, wmesg, timo) \
77     ssleep(state, &state->lock, 0, wmesg, timo)
78
79 #define STATE_WAKEUP(state)     \
80     wakeup(state)
81
82 static void csprng_reseed_callout(void *arg);
83 static int csprng_reseed(struct csprng_state *state);
84
85 static struct timeval csprng_reseed_interval = { 0, 100000 };
86
87 static
88 int
89 csprng_pool_init(struct csprng_pool *pool, uint8_t *buf, size_t len)
90 {
91         pool->bytes = 0;
92         SHA256_Init(&pool->hash_ctx);
93
94         if (len > 0)
95                 SHA256_Update(&pool->hash_ctx, buf, len);
96
97         return 0;
98 }
99
100 int
101 csprng_init(struct csprng_state *state)
102 {
103         int i, r;
104
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));
109
110         state->nonce = 0;
111         state->ctr   = 0;
112         state->reseed_cnt = 0;
113         state->failed_reseeds = 0;
114         state->callout_based_reseed = 0;
115
116         STATE_LOCK_INIT(state);
117
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]);
123         }
124
125         return r;
126 }
127
128 int
129 csprng_init_reseed(struct csprng_state *state)
130 {
131         state->callout_based_reseed = 1;
132
133         callout_init_mp(&state->reseed_callout);
134         callout_reset(&state->reseed_callout, MIN_RESEED_INTERVAL,
135                       csprng_reseed_callout, state);
136
137         return 0;
138 }
139
140 /*
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.
145  */
146
147 static
148 int
149 encrypt_bytes(struct csprng_state *state, uint8_t *out, uint8_t *in,
150               size_t bytes)
151 {
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);
157         }
158
159         chacha_encrypt_bytes(&state->cipher_ctx, in, out, (uint32_t)bytes);
160
161         return 0;
162 }
163
164 /*
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.
168  */
169 int
170 csprng_get_random(struct csprng_state *state, uint8_t *out, int bytes,
171                   int flags __unused)
172 {
173         int cnt;
174         int total_bytes = 0;
175
176         /*
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).
181          */
182         bzero(out, bytes);
183
184         STATE_LOCK(state);
185
186 again:
187         if (!state->callout_based_reseed &&
188              ratecheck(&state->last_reseed, &csprng_reseed_interval)) {
189                 csprng_reseed(state);
190         }
191
192         /*
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).
197          */
198         if (state->reseed_cnt == 0) {
199                 STATE_SLEEP(state, "csprngrsd", 0);
200                 goto again;
201         }
202
203         while (bytes > 0) {
204                 /* Limit amount of output without rekeying to 2^20 */
205                 cnt = (bytes > (1 << 20)) ? (1 << 20) : bytes;
206
207                 encrypt_bytes(state, out, out, cnt);
208
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));
214
215                 out += cnt;
216                 bytes -= cnt;
217                 total_bytes += cnt;
218         }
219
220         STATE_UNLOCK(state);
221
222         return total_bytes;
223 }
224
225 static
226 int
227 csprng_reseed(struct csprng_state *state)
228 {
229         int i;
230         struct csprng_pool *pool;
231         SHA256_CTX hash_ctx;
232         uint8_t digest[SHA256_DIGEST_LENGTH];
233
234         /*
235          * If there's not enough entropy in the first
236          * pool, don't reseed.
237          */
238         if (state->pool[0].bytes < MIN_POOL_SIZE) {
239                 ++state->failed_reseeds;
240                 return 1;
241         }
242
243         SHA256_Init(&hash_ctx);
244
245         /*
246          * Update hash that will result in new key with the
247          * old key.
248          */
249         SHA256_Update(&hash_ctx, state->key, sizeof(state->key));
250
251         state->reseed_cnt++;
252
253         for (i = 0; i < 32; i++) {
254                 if ((state->reseed_cnt % (1 << i)) != 0)
255                         break;
256
257                 pool = &state->pool[i];
258                 POOL_LOCK(pool);
259
260                 /*
261                  * Finalize hash of the entropy in this pool.
262                  */
263                 SHA256_Final(digest, &pool->hash_ctx);
264
265                 /*
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.
269                  */
270                 csprng_pool_init(pool, digest, sizeof(digest));
271
272                 POOL_UNLOCK(pool);
273
274                 /*
275                  * Update hash that will result in new key with this
276                  * pool's hashed entropy.
277                  */
278                 SHA256_Update(&hash_ctx, digest, sizeof(digest));
279         }
280
281         SHA256_Final(state->key, &hash_ctx);
282
283         /* Update key and rekey cipher */
284         chacha_keysetup(&state->cipher_ctx, state->key,
285             8*sizeof(state->key));
286
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);
292         }
293
294         return 0;
295 }
296
297 static
298 void
299 csprng_reseed_callout(void *arg)
300 {
301         struct csprng_state *state = (struct csprng_state *)arg;
302         int reseed_interval = MIN_RESEED_INTERVAL;
303
304         STATE_LOCK(state);
305
306         csprng_reseed(arg);
307
308         STATE_WAKEUP(state);
309         STATE_UNLOCK(state);
310
311         callout_reset(&state->reseed_callout, reseed_interval,
312             csprng_reseed_callout, state);
313 }
314
315 int
316 csprng_add_entropy(struct csprng_state *state, int src_id,
317                    const uint8_t *entropy, size_t bytes, int flags)
318 {
319         struct csprng_pool *pool;
320         int pool_id;
321
322         /*
323          * Pick the next pool for this source on a round-robin
324          * basis.
325          */
326         src_id &= 0xff;
327         pool_id = state->src_pool_idx[src_id]++ & 0x1f;
328         pool = &state->pool[pool_id];
329
330         if (flags & CSPRNG_TRYLOCK) {
331                 /*
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.
335                  */
336                 if (!POOL_TRYLOCK(pool))
337                         return -1;
338         } else {
339                 POOL_LOCK(pool);
340         }
341
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);
347
348         pool->bytes += bytes;
349
350         POOL_UNLOCK(pool);
351
352         /*
353          * If a wakeup is missed, it doesn't matter too much - it'll get
354          * woken up by the next add_entropy() call.
355          */
356         STATE_WAKEUP(state);
357
358         return 0;
359 }