]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/random/yarrow.c
This commit was generated by cvs2svn to compensate for changes in r159248,
[FreeBSD/FreeBSD.git] / sys / dev / random / yarrow.c
1 /*-
2  * Copyright (c) 2000-2004 Mark R V Murray
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
14  *
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.
25  *
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/param.h>
32 #include <sys/kernel.h>
33 #include <sys/lock.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>
39
40 #include <crypto/rijndael/rijndael-api-fst.h>
41 #include <crypto/sha2/sha2.h>
42
43 #include <dev/random/hash.h>
44 #include <dev/random/randomdev_soft.h>
45 #include <dev/random/yarrow.h>
46
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);
52
53 /* Structure holding the entropy state */
54 static struct random_state random_state;
55
56 static void generator_gate(void);
57 static void reseed(u_int);
58
59 /* The reseed thread mutex */
60 struct mtx random_reseed_mtx;
61
62 /* Process a single stochastic event off the harvest queue */
63 void
64 random_process_event(struct harvest *event)
65 {
66         u_int pl, overthreshhold[2];
67         struct source *source;
68         enum esource src;
69
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;
79         source->frac %= 1024;
80
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)
87                                 overthreshhold[pl]++;
88                 }
89         }
90
91         /* if any fast source over threshhold, reseed */
92         if (overthreshhold[FAST])
93                 reseed(FAST);
94
95         /* if enough slow sources are over threshhold, reseed */
96         if (overthreshhold[SLOW] >= random_state.slowoverthresh)
97                 reseed(SLOW);
98
99         /* Invert the fast/slow pool selector bit */
100         random_state.which = !random_state.which;
101 }
102
103 void
104 random_yarrow_init_alg(struct sysctl_ctx_list *clist, struct sysctl_oid *in_o)
105 {
106         int i;
107         struct sysctl_oid *o, *random_yarrow_o;
108
109         /* Yarrow parameters. Do not adjust these unless you have
110          * have a very good clue about what they do!
111          */
112         o = SYSCTL_ADD_NODE(clist,
113                 SYSCTL_CHILDREN(in_o),
114                 OID_AUTO, "yarrow", CTLFLAG_RW, 0,
115                 "Yarrow Parameters");
116
117         random_yarrow_o = o;
118
119         o = SYSCTL_ADD_PROC(clist,
120                 SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
121                 "gengateinterval", CTLTYPE_INT|CTLFLAG_RW,
122                 &random_state.gengateinterval, 10,
123                 random_check_uint_gengateinterval, "I",
124                 "Generation gate interval");
125
126         o = SYSCTL_ADD_PROC(clist,
127                 SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
128                 "bins", CTLTYPE_INT|CTLFLAG_RW,
129                 &random_state.bins, 10,
130                 random_check_uint_bins, "I",
131                 "Execution time tuner");
132
133         o = SYSCTL_ADD_PROC(clist,
134                 SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
135                 "fastthresh", CTLTYPE_INT|CTLFLAG_RW,
136                 &random_state.pool[0].thresh, (3*BLOCKSIZE)/4,
137                 random_check_uint_fastthresh, "I",
138                 "Fast reseed threshold");
139
140         o = SYSCTL_ADD_PROC(clist,
141                 SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
142                 "slowthresh", CTLTYPE_INT|CTLFLAG_RW,
143                 &random_state.pool[1].thresh, BLOCKSIZE,
144                 random_check_uint_slowthresh, "I",
145                 "Slow reseed threshold");
146
147         o = SYSCTL_ADD_PROC(clist,
148                 SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
149                 "slowoverthresh", CTLTYPE_INT|CTLFLAG_RW,
150                 &random_state.slowoverthresh, 2,
151                 random_check_uint_slowoverthresh, "I",
152                 "Slow over-threshold reseed");
153
154         random_state.gengateinterval = 10;
155         random_state.bins = 10;
156         random_state.pool[0].thresh = (3*BLOCKSIZE)/4;
157         random_state.pool[1].thresh = BLOCKSIZE;
158         random_state.slowoverthresh = 2;
159         random_state.which = FAST;
160
161         /* Initialise the fast and slow entropy pools */
162         for (i = 0; i < 2; i++)
163                 yarrow_hash_init(&random_state.pool[i].hash);
164
165         /* Clear the counter */
166         for (i = 0; i < 4; i++)
167                 random_state.counter[i] = 0;
168
169         /* Set up a lock for the reseed process */
170         mtx_init(&random_reseed_mtx, "random reseed", NULL, MTX_DEF);
171 }
172
173 void
174 random_yarrow_deinit_alg(void)
175 {
176         mtx_destroy(&random_reseed_mtx);
177 }
178
179 static void
180 reseed(u_int fastslow)
181 {
182         /* Interrupt-context stack is a limited resource; make large
183          * structures static.
184          */
185         static u_char v[TIMEBIN][KEYSIZE];      /* v[i] */
186         static struct yarrowhash context;
187         u_char hash[KEYSIZE];                   /* h' */
188         u_char temp[KEYSIZE];
189         u_int i;
190         enum esource j;
191
192         /* The reseed task must not be jumped on */
193         mtx_lock(&random_reseed_mtx);
194
195         /* 1. Hash the accumulated entropy into v[0] */
196
197         yarrow_hash_init(&context);
198         /* Feed the slow pool hash in if slow */
199         if (fastslow == SLOW)
200                 yarrow_hash_iterate(&context,
201                         &random_state.pool[SLOW].hash,
202                         sizeof(struct yarrowhash));
203         yarrow_hash_iterate(&context,
204                 &random_state.pool[FAST].hash, sizeof(struct yarrowhash));
205         yarrow_hash_finish(&context, v[0]);
206
207         /* 2. Compute hash values for all v. _Supposed_ to be computationally
208          *    intensive.
209          */
210
211         if (random_state.bins > TIMEBIN)
212                 random_state.bins = TIMEBIN;
213         for (i = 1; i < random_state.bins; i++) {
214                 yarrow_hash_init(&context);
215                 /* v[i] #= h(v[i - 1]) */
216                 yarrow_hash_iterate(&context, v[i - 1], KEYSIZE);
217                 /* v[i] #= h(v[0]) */
218                 yarrow_hash_iterate(&context, v[0], KEYSIZE);
219                 /* v[i] #= h(i) */
220                 yarrow_hash_iterate(&context, &i, sizeof(u_int));
221                 /* Return the hashval */
222                 yarrow_hash_finish(&context, v[i]);
223         }
224
225         /* 3. Compute a new key; h' is the identity function here;
226          *    it is not being ignored!
227          */
228
229         yarrow_hash_init(&context);
230         yarrow_hash_iterate(&context, &random_state.key, KEYSIZE);
231         for (i = 1; i < random_state.bins; i++)
232                 yarrow_hash_iterate(&context, &v[i], KEYSIZE);
233         yarrow_hash_finish(&context, temp);
234         yarrow_encrypt_init(&random_state.key, temp);
235
236         /* 4. Recompute the counter */
237
238         for (i = 0; i < 4; i++)
239                 random_state.counter[i] = 0;
240         yarrow_encrypt(&random_state.key, random_state.counter, temp);
241         memcpy(random_state.counter, temp, sizeof(random_state.counter));
242
243         /* 5. Reset entropy estimate accumulators to zero */
244
245         for (i = 0; i <= fastslow; i++) {
246                 for (j = RANDOM_START; j < ENTROPYSOURCE; j++) {
247                         random_state.pool[i].source[j].bits = 0;
248                         random_state.pool[i].source[j].frac = 0;
249                 }
250         }
251
252         /* 6. Wipe memory of intermediate values */
253
254         memset((void *)v, 0, sizeof(v));
255         memset((void *)temp, 0, sizeof(temp));
256         memset((void *)hash, 0, sizeof(hash));
257
258         /* 7. Dump to seed file */
259         /* XXX Not done here yet */
260
261         /* Unblock the device if it was blocked due to being unseeded */
262         random_yarrow_unblock();
263
264         /* Release the reseed mutex */
265         mtx_unlock(&random_reseed_mtx);
266 }
267
268 /* Internal function to return processed entropy from the PRNG */
269 int
270 random_yarrow_read(void *buf, int count)
271 {
272         static int cur = 0;
273         static int gate = 1;
274         static u_char genval[KEYSIZE];
275         size_t tomove;
276         int i;
277         int retval;
278
279         /* The reseed task must not be jumped on */
280         mtx_lock(&random_reseed_mtx);
281
282         if (gate) {
283                 generator_gate();
284                 random_state.outputblocks = 0;
285                 gate = 0;
286         }
287         if (count > 0 && (size_t)count >= sizeof(random_state.counter)) {
288                 retval = 0;
289                 for (i = 0; i < count; i += (int)sizeof(random_state.counter)) {
290                         random_state.counter[0]++;
291                         yarrow_encrypt(&random_state.key, random_state.counter,
292                                 genval);
293                         tomove = min(count - i, sizeof(random_state.counter));
294                         memcpy((char *)buf + i, genval, tomove);
295                         if (++random_state.outputblocks >=
296                                 random_state.gengateinterval) {
297                                 generator_gate();
298                                 random_state.outputblocks = 0;
299                         }
300                         retval += (int)tomove;
301                 }
302         }
303         else {
304                 if (!cur) {
305                         random_state.counter[0]++;
306                         yarrow_encrypt(&random_state.key, random_state.counter,
307                                 genval);
308                         memcpy(buf, genval, (size_t)count);
309                         cur = (int)sizeof(random_state.counter) - count;
310                         if (++random_state.outputblocks >=
311                                 random_state.gengateinterval) {
312                                 generator_gate();
313                                 random_state.outputblocks = 0;
314                         }
315                         retval = count;
316                 }
317                 else {
318                         retval = MIN(cur, count);
319                         memcpy(buf,
320                             &genval[(int)sizeof(random_state.counter) - cur],
321                             (size_t)retval);
322                         cur -= retval;
323                 }
324         }
325         mtx_unlock(&random_reseed_mtx);
326         return retval;
327 }
328
329 static void
330 generator_gate(void)
331 {
332         u_int i;
333         u_char temp[KEYSIZE];
334
335         for (i = 0; i < KEYSIZE; i += sizeof(random_state.counter)) {
336                 random_state.counter[0]++;
337                 yarrow_encrypt(&random_state.key, random_state.counter,
338                         &(temp[i]));
339         }
340
341         yarrow_encrypt_init(&random_state.key, temp);
342         memset((void *)temp, 0, KEYSIZE);
343
344 }
345
346 /* Helper routine to perform explicit reseeds */
347 void
348 random_yarrow_reseed(void)
349 {
350         reseed(SLOW);
351 }