contrib/libpcap: Revert local modification for vendor update
[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 #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 }