2 * Copyright (c) 2000-2004 Mark R V Murray
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer
10 * in this position and unchanged.
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.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/param.h>
32 #include <sys/kernel.h>
34 #include <sys/malloc.h>
35 #include <sys/mutex.h>
36 #include <sys/random.h>
37 #include <sys/sysctl.h>
38 #include <sys/systm.h>
40 #include <crypto/rijndael/rijndael-api-fst.h>
41 #include <crypto/sha2/sha2.h>
43 #include <dev/random/hash.h>
44 #include <dev/random/randomdev_soft.h>
45 #include <dev/random/yarrow.h>
47 RANDOM_CHECK_UINT(gengateinterval, 4, 64);
48 RANDOM_CHECK_UINT(bins, 2, 16);
49 RANDOM_CHECK_UINT(fastthresh, BLOCKSIZE/4, BLOCKSIZE);
50 RANDOM_CHECK_UINT(slowthresh, BLOCKSIZE/4, BLOCKSIZE);
51 RANDOM_CHECK_UINT(slowoverthresh, 1, 5);
53 /* Structure holding the entropy state */
54 static struct random_state random_state;
56 static void generator_gate(void);
57 static void reseed(u_int);
59 /* The reseed thread mutex */
60 struct mtx random_reseed_mtx;
62 /* Process a single stochastic event off the harvest queue */
64 random_process_event(struct harvest *event)
66 u_int pl, overthreshhold[2];
67 struct source *source;
70 /* Unpack the event into the appropriate source accumulator */
71 pl = random_state.which;
72 source = &random_state.pool[pl].source[event->source];
73 yarrow_hash_iterate(&random_state.pool[pl].hash, event->entropy,
74 sizeof(event->entropy));
75 yarrow_hash_iterate(&random_state.pool[pl].hash, &event->somecounter,
76 sizeof(event->somecounter));
77 source->frac += event->frac;
78 source->bits += event->bits + source->frac/1024;
81 /* Count the over-threshold sources in each pool */
82 for (pl = 0; pl < 2; pl++) {
83 overthreshhold[pl] = 0;
84 for (src = RANDOM_START; src < ENTROPYSOURCE; src++) {
85 if (random_state.pool[pl].source[src].bits
86 > random_state.pool[pl].thresh)
91 /* if any fast source over threshhold, reseed */
92 if (overthreshhold[FAST])
95 /* if enough slow sources are over threshhold, reseed */
96 if (overthreshhold[SLOW] >= random_state.slowoverthresh)
99 /* Invert the fast/slow pool selector bit */
100 random_state.which = !random_state.which;
104 random_yarrow_init_alg(struct sysctl_ctx_list *clist, struct sysctl_oid *in_o)
107 struct sysctl_oid *random_yarrow_o;
109 /* Yarrow parameters. Do not adjust these unless you have
110 * have a very good clue about what they do!
112 random_yarrow_o = SYSCTL_ADD_NODE(clist,
113 SYSCTL_CHILDREN(in_o),
114 OID_AUTO, "yarrow", CTLFLAG_RW, 0,
115 "Yarrow Parameters");
117 SYSCTL_ADD_PROC(clist,
118 SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
119 "gengateinterval", CTLTYPE_INT|CTLFLAG_RW,
120 &random_state.gengateinterval, 10,
121 random_check_uint_gengateinterval, "I",
122 "Generation gate interval");
124 SYSCTL_ADD_PROC(clist,
125 SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
126 "bins", CTLTYPE_INT|CTLFLAG_RW,
127 &random_state.bins, 10,
128 random_check_uint_bins, "I",
129 "Execution time tuner");
131 SYSCTL_ADD_PROC(clist,
132 SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
133 "fastthresh", CTLTYPE_INT|CTLFLAG_RW,
134 &random_state.pool[0].thresh, (3*BLOCKSIZE)/4,
135 random_check_uint_fastthresh, "I",
136 "Fast reseed threshold");
138 SYSCTL_ADD_PROC(clist,
139 SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
140 "slowthresh", CTLTYPE_INT|CTLFLAG_RW,
141 &random_state.pool[1].thresh, BLOCKSIZE,
142 random_check_uint_slowthresh, "I",
143 "Slow reseed threshold");
145 SYSCTL_ADD_PROC(clist,
146 SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
147 "slowoverthresh", CTLTYPE_INT|CTLFLAG_RW,
148 &random_state.slowoverthresh, 2,
149 random_check_uint_slowoverthresh, "I",
150 "Slow over-threshold reseed");
152 random_state.gengateinterval = 10;
153 random_state.bins = 10;
154 random_state.pool[0].thresh = (3*BLOCKSIZE)/4;
155 random_state.pool[1].thresh = BLOCKSIZE;
156 random_state.slowoverthresh = 2;
157 random_state.which = FAST;
159 /* Initialise the fast and slow entropy pools */
160 for (i = 0; i < 2; i++)
161 yarrow_hash_init(&random_state.pool[i].hash);
163 /* Clear the counter */
164 for (i = 0; i < 4; i++)
165 random_state.counter[i] = 0;
167 /* Set up a lock for the reseed process */
168 mtx_init(&random_reseed_mtx, "random reseed", NULL, MTX_DEF);
172 random_yarrow_deinit_alg(void)
174 mtx_destroy(&random_reseed_mtx);
178 reseed(u_int fastslow)
180 /* Interrupt-context stack is a limited resource; make large
183 static u_char v[TIMEBIN][KEYSIZE]; /* v[i] */
184 static struct yarrowhash context;
185 u_char hash[KEYSIZE]; /* h' */
186 u_char temp[KEYSIZE];
190 /* The reseed task must not be jumped on */
191 mtx_lock(&random_reseed_mtx);
193 /* 1. Hash the accumulated entropy into v[0] */
195 yarrow_hash_init(&context);
196 /* Feed the slow pool hash in if slow */
197 if (fastslow == SLOW)
198 yarrow_hash_iterate(&context,
199 &random_state.pool[SLOW].hash,
200 sizeof(struct yarrowhash));
201 yarrow_hash_iterate(&context,
202 &random_state.pool[FAST].hash, sizeof(struct yarrowhash));
203 yarrow_hash_finish(&context, v[0]);
205 /* 2. Compute hash values for all v. _Supposed_ to be computationally
209 if (random_state.bins > TIMEBIN)
210 random_state.bins = TIMEBIN;
211 for (i = 1; i < random_state.bins; i++) {
212 yarrow_hash_init(&context);
213 /* v[i] #= h(v[i - 1]) */
214 yarrow_hash_iterate(&context, v[i - 1], KEYSIZE);
215 /* v[i] #= h(v[0]) */
216 yarrow_hash_iterate(&context, v[0], KEYSIZE);
218 yarrow_hash_iterate(&context, &i, sizeof(u_int));
219 /* Return the hashval */
220 yarrow_hash_finish(&context, v[i]);
223 /* 3. Compute a new key; h' is the identity function here;
224 * it is not being ignored!
227 yarrow_hash_init(&context);
228 yarrow_hash_iterate(&context, &random_state.key, KEYSIZE);
229 for (i = 1; i < random_state.bins; i++)
230 yarrow_hash_iterate(&context, &v[i], KEYSIZE);
231 yarrow_hash_finish(&context, temp);
232 yarrow_encrypt_init(&random_state.key, temp);
234 /* 4. Recompute the counter */
236 for (i = 0; i < 4; i++)
237 random_state.counter[i] = 0;
238 yarrow_encrypt(&random_state.key, random_state.counter, temp);
239 memcpy(random_state.counter, temp, sizeof(random_state.counter));
241 /* 5. Reset entropy estimate accumulators to zero */
243 for (i = 0; i <= fastslow; i++) {
244 for (j = RANDOM_START; j < ENTROPYSOURCE; j++) {
245 random_state.pool[i].source[j].bits = 0;
246 random_state.pool[i].source[j].frac = 0;
250 /* 6. Wipe memory of intermediate values */
252 memset((void *)v, 0, sizeof(v));
253 memset((void *)temp, 0, sizeof(temp));
254 memset((void *)hash, 0, sizeof(hash));
256 /* 7. Dump to seed file */
257 /* XXX Not done here yet */
259 /* Unblock the device if it was blocked due to being unseeded */
260 random_yarrow_unblock();
262 /* Release the reseed mutex */
263 mtx_unlock(&random_reseed_mtx);
266 /* Internal function to return processed entropy from the PRNG */
268 random_yarrow_read(void *buf, int count)
272 static u_char genval[KEYSIZE];
277 /* The reseed task must not be jumped on */
278 mtx_lock(&random_reseed_mtx);
282 random_state.outputblocks = 0;
285 if (count > 0 && (size_t)count >= sizeof(random_state.counter)) {
287 for (i = 0; i < count; i += (int)sizeof(random_state.counter)) {
288 random_state.counter[0]++;
289 yarrow_encrypt(&random_state.key, random_state.counter,
291 tomove = min(count - i, sizeof(random_state.counter));
292 memcpy((char *)buf + i, genval, tomove);
293 if (++random_state.outputblocks >=
294 random_state.gengateinterval) {
296 random_state.outputblocks = 0;
298 retval += (int)tomove;
304 random_state.counter[0]++;
305 yarrow_encrypt(&random_state.key, random_state.counter,
307 memcpy(buf, genval, (size_t)count);
308 cur = (int)sizeof(random_state.counter) - count;
309 if (++random_state.outputblocks >=
310 random_state.gengateinterval) {
312 random_state.outputblocks = 0;
317 retval = MIN(cur, count);
319 &genval[(int)sizeof(random_state.counter) - cur],
324 mtx_unlock(&random_reseed_mtx);
332 u_char temp[KEYSIZE];
334 for (i = 0; i < KEYSIZE; i += sizeof(random_state.counter)) {
335 random_state.counter[0]++;
336 yarrow_encrypt(&random_state.key, random_state.counter,
340 yarrow_encrypt_init(&random_state.key, temp);
341 memset((void *)temp, 0, KEYSIZE);
345 /* Helper routine to perform explicit reseeds */
347 random_yarrow_reseed(void)