csprng - don't wait for entropy for the ratectl'ed reseed
[dragonfly.git] / sys / kern / subr_csprng.c
1 #include <sys/param.h>
2 #include <sys/systm.h>
3 #include <sys/kernel.h>
4 #include <sys/spinlock.h>
5 #include <sys/spinlock2.h>
6 #include <sys/csprng.h>
7
8 /*
9  * Minimum amount of bytes in pool before we consider it
10  * good enough.
11  * It's 64 + the hash digest size because we always
12  * reinitialize the pools with a hash of the previous chunk
13  * of entropy.
14  */
15 #define MIN_POOL_SIZE   64 + SHA256_DIGEST_LENGTH
16
17 /* Minimum reseed interval */
18 #define MIN_RESEED_INTERVAL     hz/10
19
20 /* Lock macros */
21 #define POOL_LOCK_INIT(pool) \
22     spin_init(&(pool)->lock)
23
24 #define POOL_LOCK(pool)      \
25     spin_lock(&pool->lock)
26
27 #define POOL_TRYLOCK(pool)   \
28     spin_trylock(&pool->lock)
29
30 #define POOL_UNLOCK(pool)    \
31     spin_unlock(&pool->lock)
32
33
34 #define STATE_LOCK_INIT(state)  \
35     spin_init(&state->lock)
36
37 #define STATE_LOCK(state)       \
38     spin_lock(&state->lock)
39
40 #define STATE_UNLOCK(state)     \
41     spin_unlock(&state->lock)
42
43 #define STATE_SLEEP(state, wmesg, timo) \
44     ssleep(state, &state->lock, 0, wmesg, timo)
45
46 #define STATE_WAKEUP(state)     \
47     wakeup(state)
48
49 static void csprng_reseed_callout(void *arg);
50 static int csprng_reseed(struct csprng_state *state);
51
52 static struct timeval csprng_reseed_interval = { 0, 100000 };
53
54 static
55 int
56 csprng_pool_init(struct csprng_pool *pool, uint8_t *buf, size_t len)
57 {
58         pool->bytes = 0;
59         SHA256_Init(&pool->hash_ctx);
60
61         if (len > 0)
62                 SHA256_Update(&pool->hash_ctx, buf, len);
63
64         return 0;
65 }
66
67 int
68 csprng_init(struct csprng_state *state)
69 {
70         int i, r;
71
72         bzero(state->key, sizeof(state->key));
73         bzero(&state->cipher_ctx, sizeof(state->cipher_ctx));
74         bzero(state->src_pool_idx, sizeof(state->src_pool_idx));
75         bzero(&state->last_reseed, sizeof(state->last_reseed));
76
77         state->nonce = 0;
78         state->ctr   = 0;
79         state->reseed_cnt = 0;
80         state->failed_reseeds = 0;
81         state->callout_based_reseed = 0;
82
83         STATE_LOCK_INIT(state);
84
85         for (i = 0; i < 32; i++) {
86                 r = csprng_pool_init(&state->pool[i], NULL, 0);
87                 if (r != 0)
88                         break;
89                 POOL_LOCK_INIT(&state->pool[i]);
90         }
91
92         return r;
93 }
94
95 int
96 csprng_init_reseed(struct csprng_state *state)
97 {
98         state->callout_based_reseed = 1;
99
100         callout_init_mp(&state->reseed_callout);
101         callout_reset(&state->reseed_callout, MIN_RESEED_INTERVAL,
102             csprng_reseed_callout, state);
103
104         return 0;
105 }
106
107 /*
108  * XXX:
109  * Sources don't really a uniquely-allocated src id...
110  * another way we could do that is by simply using
111  * (uint8_t)__LINE__ as the source id... cheap & cheerful.
112  */
113
114 static
115 int
116 encrypt_bytes(struct csprng_state *state, uint8_t *out, uint8_t *in, size_t bytes)
117 {
118         /* Update nonce whenever the counter is about to overflow */
119         if (chacha_check_counter(&state->cipher_ctx)) {
120                 ++state->nonce;
121                 chacha_ivsetup(&state->cipher_ctx, (const uint8_t *)&state->nonce);
122         }
123
124         chacha_encrypt_bytes(&state->cipher_ctx, in, out, (uint32_t)bytes);
125
126         return 0;
127 }
128
129 /*
130  * XXX: flags is currently unused, but could be used to know whether
131  *      it's a /dev/random or /dev/urandom read, and make sure that
132  *      enough entropy has been collected recently, etc.
133  */
134 int
135 csprng_get_random(struct csprng_state *state, uint8_t *out, int bytes,
136     int flags __unused)
137 {
138         int cnt;
139         int total_bytes = 0;
140         int r;
141
142         /*
143          * XXX: can optimize a bit by digging into chacha_encrypt_bytes
144          *      and removing the xor of the stream with the input - that
145          *      way we don't have to xor the output (which we provide
146          *      as input).
147          */
148         bzero(out, bytes);
149
150         STATE_LOCK(state);
151
152 again:
153         if (!state->callout_based_reseed &&
154              ratecheck(&state->last_reseed, &csprng_reseed_interval)) {
155                 csprng_reseed(state);
156         }
157
158         KKASSERT(state->reseed_cnt >= 0);
159
160         if (state->reseed_cnt == 0) {
161                 STATE_SLEEP(state, "csprngrsd", 0);
162                 goto again;
163         }
164
165         while (bytes > 0) {
166                 /* Limit amount of output without rekeying to 2^20 */
167                 cnt = (bytes > (1 << 20)) ? (1 << 20) : bytes;
168
169                 encrypt_bytes(state, out, out, cnt);
170
171                 /* Update key and rekey cipher */
172                 encrypt_bytes(state, state->key, state->key, sizeof(state->key));
173                 chacha_keysetup(&state->cipher_ctx, state->key,
174                     8*sizeof(state->key));
175
176                 out += cnt;
177                 bytes -= cnt;
178                 total_bytes += cnt;
179         }
180
181         STATE_UNLOCK(state);
182
183         return total_bytes;
184 }
185
186 static
187 int
188 csprng_reseed(struct csprng_state *state)
189 {
190         int i;
191         struct csprng_pool *pool;
192         SHA256_CTX hash_ctx;
193         uint8_t digest[SHA256_DIGEST_LENGTH];
194
195         /*
196          * If there's not enough entropy in the first
197          * pool, don't reseed.
198          */
199         if (state->pool[0].bytes < MIN_POOL_SIZE) {
200                 ++state->failed_reseeds;
201                 return 1;
202         }
203
204         SHA256_Init(&hash_ctx);
205
206         /*
207          * Update hash that will result in new key with the
208          * old key.
209          */
210         SHA256_Update(&hash_ctx, state->key, sizeof(state->key));
211
212         state->reseed_cnt++;
213
214         for (i = 0; i < 32; i++) {
215                 if ((state->reseed_cnt % (1 << i)) != 0)
216                         break;
217
218                 pool = &state->pool[i];
219                 POOL_LOCK(pool);
220
221                 /*
222                  * Finalize hash of the entropy in this pool.
223                  */
224                 SHA256_Final(digest, &pool->hash_ctx);
225
226                 /*
227                  * Reinitialize pool with a hash of the old pool digest.
228                  * This is a slight deviation from Fortuna as per reference,
229                  * but is in line with other Fortuna implementations.
230                  */
231                 csprng_pool_init(pool, digest, sizeof(digest));
232
233                 POOL_UNLOCK(pool);
234
235                 /*
236                  * Update hash that will result in new key with this
237                  * pool's hashed entropy.
238                  */
239                 SHA256_Update(&hash_ctx, digest, sizeof(digest));
240         }
241
242         SHA256_Final(state->key, &hash_ctx);
243
244         /* Update key and rekey cipher */
245         chacha_keysetup(&state->cipher_ctx, state->key,
246             8*sizeof(state->key));
247
248         /* Increment the nonce if the counter overflows */
249         if (chacha_incr_counter(&state->cipher_ctx)) {
250                 ++state->nonce;
251                 chacha_ivsetup(&state->cipher_ctx, (const uint8_t *)&state->nonce);
252         }
253
254         return 0;
255 }
256
257 static
258 void
259 csprng_reseed_callout(void *arg)
260 {
261         struct csprng_state *state = (struct csprng_state *)arg;
262         int reseed_interval = MIN_RESEED_INTERVAL;
263
264         STATE_LOCK(state);
265
266         csprng_reseed(arg);
267
268         STATE_WAKEUP(state);
269         STATE_UNLOCK(state);
270
271         callout_reset(&state->reseed_callout, reseed_interval,
272             csprng_reseed_callout, state);
273 }
274
275 int
276 csprng_add_entropy(struct csprng_state *state, int src_id,
277     const uint8_t *entropy, size_t bytes, int flags)
278 {
279         struct csprng_pool *pool;
280         int pool_id;
281
282         /*
283          * Pick the next pool for this source on a round-robin
284          * basis.
285          */
286         src_id &= 0xff;
287         pool_id = state->src_pool_idx[src_id]++ & 0x1f;
288         pool = &state->pool[pool_id];
289
290         if (flags & CSPRNG_TRYLOCK) {
291                 /*
292                  * If we are asked to just try the lock instead
293                  * of spinning until we get it, return if we
294                  * can't get a hold of the lock right now.
295                  */
296                 if (!POOL_TRYLOCK(pool))
297                         return -1;
298         } else {
299                 POOL_LOCK(pool);
300         }
301
302         SHA256_Update(&pool->hash_ctx, (const uint8_t *)&src_id, sizeof(src_id));
303         SHA256_Update(&pool->hash_ctx, (const uint8_t *)&bytes, sizeof(bytes));
304         SHA256_Update(&pool->hash_ctx, entropy, bytes);
305
306         pool->bytes += bytes;
307
308         POOL_UNLOCK(pool);
309
310         /*
311          * If a wakeup is missed, it doesn't matter too much - it'll get woken
312          * up by the next add_entropy() call.
313          */
314         STATE_WAKEUP(state);
315
316         return 0;
317 }