1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2019 Conrad Meyer <cem@FreeBSD.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/param.h>
29 #include <sys/fail.h>
30 #include <sys/limits.h>
31 #include <sys/lock.h>
32 #include <sys/kernel.h>
33 #include <sys/malloc.h>
34 #include <sys/mutex.h>
35 #include <sys/random.h>
36 #include <sys/sdt.h>
37 #include <sys/sysctl.h>
38 #include <sys/systm.h>
39
40 #include <machine/cpu.h>
41 #include <machine/stdarg.h>
42
43 #define CHACHA_EMBED
44 #define KEYSTREAM_ONLY
45 #define CHACHA_NONCE0_CTR128
46 #include <crypto/chacha20/chacha.h>
47 #include <crypto/rijndael/rijndael-api-fst.h>
48 #include <crypto/sha2/sha256.h>
49
50 #include <dev/random/hash.h>
51 #include <dev/random/randomdev.h>
52 #include <dev/random/random_harvestq.h>
53 #include <dev/random/uint128.h>
54
55 #include <dev/random/fenestrasX/fx_hash.h>
56 #include <dev/random/fenestrasX/fx_priv.h>
57 #include <dev/random/fenestrasX/fx_rng.h>
58
59 _Static_assert(FX_CHACHA20_KEYSIZE == RANDOM_KEYSIZE, "");
60
61 #include <crypto/chacha20/chacha.c>
62
63 static void
fxrng_rng_keystream_internal(struct chacha_ctx * prf,void * buf,size_t nbytes)64 fxrng_rng_keystream_internal(struct chacha_ctx *prf, void *buf, size_t nbytes)
65 {
66 size_t chunklen;
67
68 while (nbytes > 0) {
69 chunklen = MIN(nbytes,
70 rounddown((size_t)UINT32_MAX, CHACHA_BLOCKLEN));
71
72 chacha_encrypt_bytes(prf, NULL, buf, chunklen);
73 buf = (uint8_t *)buf + chunklen;
74 nbytes -= chunklen;
75 }
76 }
77
78 /*
79 * This subroutine pulls the counter out of Chacha, which for whatever reason
80 * always encodes and decodes counters in a little endian format, and adds
81 * 'addend' to it, saving the result in Chacha.
82 */
83 static void
fxrng_chacha_nonce_add64(struct chacha_ctx * ctx,uint64_t addend)84 fxrng_chacha_nonce_add64(struct chacha_ctx *ctx, uint64_t addend)
85 {
86 uint128_t ctr; /* Native-endian. */
87 #if BYTE_ORDER == BIG_ENDIAN
88 uint128_t lectr;
89
90 chacha_ctrsave(ctx, (void *)&lectr);
91 ctr = le128dec(&lectr);
92 #else
93 chacha_ctrsave(ctx, (void *)&ctr);
94 #endif
95
96 uint128_add64(&ctr, addend);
97
98 /* chacha_ivsetup() does not modify the key, and we rely on that. */
99 #if BYTE_ORDER == BIG_ENDIAN
100 le128enc(&lectr, ctr);
101 chacha_ivsetup(ctx, NULL, (const void *)&lectr);
102 explicit_bzero(&lectr, sizeof(lectr));
103 #else
104 chacha_ivsetup(ctx, NULL, (const void *)&ctr);
105 #endif
106 explicit_bzero(&ctr, sizeof(ctr));
107 }
108
109 /*
110 * Generate from the unbuffered source PRNG.
111 *
112 * Handles fast key erasure (rekeys the PRF with a generated key under lock).
113 *
114 * RNG lock is required on entry. If return_unlocked is true, RNG lock will
115 * be dropped on return.
116 */
117 void
fxrng_rng_genrandom_internal(struct fxrng_basic_rng * rng,void * buf,size_t nbytes,bool return_unlocked)118 fxrng_rng_genrandom_internal(struct fxrng_basic_rng *rng, void *buf,
119 size_t nbytes, bool return_unlocked)
120 {
121 struct chacha_ctx ctx_copy, *p_ctx;
122 uint8_t newkey[FX_CHACHA20_KEYSIZE];
123 size_t blockcount;
124
125 FXRNG_RNG_ASSERT(rng);
126
127 /* Save off the initial output of the generator for rekeying. */
128 fxrng_rng_keystream_internal(&rng->rng_prf, newkey, sizeof(newkey));
129
130 if (return_unlocked) {
131 memcpy(&ctx_copy, &rng->rng_prf, sizeof(ctx_copy));
132 p_ctx = &ctx_copy;
133
134 /*
135 * Forward the Chacha counter state over the blocks we promise
136 * to generate for the caller without the lock.
137 */
138 blockcount = howmany(nbytes, CHACHA_BLOCKLEN);
139 fxrng_chacha_nonce_add64(&rng->rng_prf, blockcount);
140
141 /* Re-key before dropping the lock. */
142 chacha_keysetup(&rng->rng_prf, newkey, sizeof(newkey) * 8);
143 explicit_bzero(newkey, sizeof(newkey));
144
145 FXRNG_RNG_UNLOCK(rng);
146 } else {
147 p_ctx = &rng->rng_prf;
148 }
149
150 fxrng_rng_keystream_internal(p_ctx, buf, nbytes);
151
152 if (return_unlocked) {
153 explicit_bzero(&ctx_copy, sizeof(ctx_copy));
154 FXRNG_RNG_ASSERT_NOT(rng);
155 } else {
156 /* Re-key before exit. */
157 chacha_keysetup(&rng->rng_prf, newkey, sizeof(newkey) * 8);
158 explicit_bzero(newkey, sizeof(newkey));
159 FXRNG_RNG_ASSERT(rng);
160 }
161 }
162
163 /*
164 * Helper to reseed the root RNG, incorporating the existing RNG state.
165 *
166 * The root RNG is locked on entry and locked on return.
167 */
168 static void
fxrng_rng_reseed_internal(struct fxrng_basic_rng * rng,bool seeded,const void * src,size_t sz,...)169 fxrng_rng_reseed_internal(struct fxrng_basic_rng *rng, bool seeded,
170 const void *src, size_t sz, ...)
171 {
172 union {
173 uint8_t root_state[FX_CHACHA20_KEYSIZE];
174 uint8_t hash_out[FXRNG_HASH_SZ];
175 } u;
176 struct fxrng_hash mix;
177 va_list ap;
178
179 _Static_assert(FX_CHACHA20_KEYSIZE <= FXRNG_HASH_SZ, "");
180
181 FXRNG_RNG_ASSERT(rng);
182
183 fxrng_hash_init(&mix);
184 if (seeded) {
185 fxrng_rng_keystream_internal(&rng->rng_prf, u.root_state,
186 sizeof(u.root_state));
187 fxrng_hash_update(&mix, u.root_state, sizeof(u.root_state));
188 }
189 fxrng_hash_update(&mix, src, sz);
190
191 va_start(ap, sz);
192 while (true) {
193 src = va_arg(ap, const void *);
194 if (src == NULL)
195 break;
196 sz = va_arg(ap, size_t);
197 fxrng_hash_update(&mix, src, sz);
198 }
199 va_end(ap);
200
201 fxrng_hash_finish(&mix, u.hash_out, sizeof(u.hash_out));
202
203 /*
204 * Take the first keysize (32) bytes of our digest (64 bytes). It is
205 * also possible to just have Blake2 emit fewer bytes, but our wrapper
206 * API doesn't provide that functionality and there isn't anything
207 * obviously wrong with emitting more hash bytes.
208 *
209 * keysetup does not reset the embedded counter, and we rely on that
210 * property.
211 */
212 chacha_keysetup(&rng->rng_prf, u.hash_out, FX_CHACHA20_KEYSIZE * 8);
213
214 /* 'mix' zeroed by fxrng_hash_finish(). */
215 explicit_bzero(u.hash_out, sizeof(u.hash_out));
216
217 FXRNG_RNG_ASSERT(rng);
218 }
219
220 /*
221 * Directly reseed the root RNG from a first-time entropy source,
222 * incorporating the existing RNG state, called by fxrng_brng_src_reseed.
223 *
224 * The root RNG is locked on entry and locked on return.
225 */
226 void
fxrng_rng_src_reseed(struct fxrng_basic_rng * rng,const struct harvest_event * event)227 fxrng_rng_src_reseed(struct fxrng_basic_rng *rng,
228 const struct harvest_event *event)
229 {
230 fxrng_rng_reseed_internal(rng, true, &event->he_somecounter,
231 sizeof(event->he_somecounter), (const void *)event->he_entropy,
232 (size_t)event->he_size, NULL);
233 }
234
235 /*
236 * Reseed the root RNG from pooled entropy, incorporating the existing RNG
237 * state, called by fxrng_brng_reseed.
238 *
239 * The root RNG is locked on entry and locked on return.
240 */
241 void
fxrng_rng_reseed(struct fxrng_basic_rng * rng,bool seeded,const void * entr,size_t sz)242 fxrng_rng_reseed(struct fxrng_basic_rng *rng, bool seeded, const void *entr,
243 size_t sz)
244 {
245 fxrng_rng_reseed_internal(rng, seeded, entr, sz, NULL);
246 }
247