proc->thread stage 4: rework the VFS and DEVICE subsystems to take thread
[dragonfly.git] / sys / kern / kern_random.c
1 /*
2  * kern_random.c -- A strong random number generator
3  *
4  * $FreeBSD: src/sys/kern/kern_random.c,v 1.36.2.4 2002/09/17 17:11:57 sam Exp $
5  * $DragonFly: src/sys/kern/Attic/kern_random.c,v 1.3 2003/06/23 17:55:41 dillon Exp $
6  *
7  * Version 0.95, last modified 18-Oct-95
8  * 
9  * Copyright Theodore Ts'o, 1994, 1995.  All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, and the entire permission notice in its entirety,
16  *    including the disclaimer of warranties.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. The name of the author may not be used to endorse or promote
21  *    products derived from this software without specific prior
22  *    written permission.
23  * 
24  * ALTERNATIVELY, this product may be distributed under the terms of
25  * the GNU Public License, in which case the provisions of the GPL are
26  * required INSTEAD OF the above restrictions.  (This clause is
27  * necessary due to a potential bad interaction between the GPL and
28  * the restrictions contained in a BSD-style copyright.)
29  * 
30  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
31  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
33  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
34  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
35  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
36  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
38  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
40  * OF THE POSSIBILITY OF SUCH DAMAGE.
41  */
42
43 #include <sys/param.h>
44 #include <sys/kernel.h>
45 #include <sys/md5.h>
46 #include <sys/poll.h>
47 #include <sys/random.h>
48 #include <sys/select.h>
49 #include <sys/systm.h>
50
51 #ifdef __i386__
52 #include <i386/isa/icu.h>
53 #endif
54 #ifdef __alpha__
55 /*
56         XXX  the below should be used.  However there is too much "16"
57         hardcodeing in kern_random.c right now. -- obrien
58 #include <machine/ipl.h>
59 #if NHWI > 0
60 #define ICU_LEN (NHWI)
61 #else
62 #define ICU_LEN (NSWI)
63 #endif
64 */
65 #define ICU_LEN 16
66 #endif
67
68 #define MAX_BLKDEV 4
69
70 /*
71  * The pool is stirred with a primitive polynomial of degree 128
72  * over GF(2), namely x^128 + x^99 + x^59 + x^31 + x^9 + x^7 + 1.
73  * For a pool of size 64, try x^64+x^62+x^38+x^10+x^6+x+1.
74  */
75 #define POOLWORDS 128    /* Power of 2 - note that this is 32-bit words */
76 #define POOLBITS (POOLWORDS*32)
77
78 #if POOLWORDS == 128
79 #define TAP1    99     /* The polynomial taps */
80 #define TAP2    59
81 #define TAP3    31
82 #define TAP4    9
83 #define TAP5    7
84 #elif POOLWORDS == 64
85 #define TAP1    62      /* The polynomial taps */
86 #define TAP2    38
87 #define TAP3    10
88 #define TAP4    6
89 #define TAP5    1
90 #else
91 #error No primitive polynomial available for chosen POOLWORDS
92 #endif
93
94 #define WRITEBUFFER 512 /* size in bytes */
95
96 /* There is actually only one of these, globally. */
97 struct random_bucket {
98         u_int   add_ptr;
99         u_int   entropy_count;
100         int     input_rotate;
101         u_int32_t *pool;
102         struct  selinfo rsel;
103 };
104
105 /* There is one of these per entropy source */
106 struct timer_rand_state {
107         u_long  last_time;
108         int     last_delta;
109         int     nbits;
110 };
111
112 static struct random_bucket random_state;
113 static u_int32_t random_pool[POOLWORDS];
114 static struct timer_rand_state keyboard_timer_state;
115 static struct timer_rand_state extract_timer_state;
116 static struct timer_rand_state irq_timer_state[ICU_LEN];
117 #ifdef notyet
118 static struct timer_rand_state blkdev_timer_state[MAX_BLKDEV];
119 #endif
120 static struct wait_queue *random_wait;
121
122 #ifndef MIN
123 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
124 #endif
125         
126 void
127 rand_initialize(void)
128 {
129         random_state.add_ptr = 0;
130         random_state.entropy_count = 0;
131         random_state.pool = random_pool;
132         random_wait = NULL;
133         random_state.rsel.si_flags = 0;
134         random_state.rsel.si_pid = 0;
135 }
136
137 /*
138  * This function adds an int into the entropy "pool".  It does not
139  * update the entropy estimate.  The caller must do this if appropriate.
140  *
141  * The pool is stirred with a primitive polynomial of degree 128
142  * over GF(2), namely x^128 + x^99 + x^59 + x^31 + x^9 + x^7 + 1.
143  * For a pool of size 64, try x^64+x^62+x^38+x^10+x^6+x+1.
144  * 
145  * We rotate the input word by a changing number of bits, to help
146  * assure that all bits in the entropy get toggled.  Otherwise, if we
147  * consistently feed the entropy pool small numbers (like ticks and
148  * scancodes, for example), the upper bits of the entropy pool don't
149  * get affected. --- TYT, 10/11/95
150  */
151 static __inline void
152 add_entropy_word(struct random_bucket *r, const u_int32_t input)
153 {
154         u_int i;
155         u_int32_t w;
156
157         w = (input << r->input_rotate) | (input >> (32 - r->input_rotate));
158         i = r->add_ptr = (r->add_ptr - 1) & (POOLWORDS-1);
159         if (i)
160                 r->input_rotate = (r->input_rotate + 7) & 31;
161         else
162                 /*
163                  * At the beginning of the pool, add an extra 7 bits
164                  * rotation, so that successive passes spread the
165                  * input bits across the pool evenly.
166                  */
167                 r->input_rotate = (r->input_rotate + 14) & 31;
168
169         /* XOR in the various taps */
170         w ^= r->pool[(i+TAP1)&(POOLWORDS-1)];
171         w ^= r->pool[(i+TAP2)&(POOLWORDS-1)];
172         w ^= r->pool[(i+TAP3)&(POOLWORDS-1)];
173         w ^= r->pool[(i+TAP4)&(POOLWORDS-1)];
174         w ^= r->pool[(i+TAP5)&(POOLWORDS-1)];
175         w ^= r->pool[i];
176         /* Rotate w left 1 bit (stolen from SHA) and store */
177         r->pool[i] = (w << 1) | (w >> 31);
178 }
179
180 /*
181  * This function adds entropy to the entropy "pool" by using timing
182  * delays.  It uses the timer_rand_state structure to make an estimate
183  * of how  any bits of entropy this call has added to the pool.
184  *
185  * The number "num" is also added to the pool - it should somehow describe
186  * the type of event which just happened.  This is currently 0-255 for
187  * keyboard scan codes, and 256 upwards for interrupts.
188  * On the i386, this is assumed to be at most 16 bits, and the high bits
189  * are used for a high-resolution timer.
190  */
191 static void
192 add_timer_randomness(struct random_bucket *r, struct timer_rand_state *state,
193         u_int num)
194 {
195         int             delta, delta2;
196         u_int           nbits;
197         u_int32_t       time;
198         struct timecounter *tc;
199
200         tc = timecounter;
201         num ^= tc->tc_get_timecount(tc) << 16;
202         r->entropy_count += 2;
203                 
204         time = ticks;
205
206         add_entropy_word(r, (u_int32_t) num);
207         add_entropy_word(r, time);
208
209         /*
210          * Calculate number of bits of randomness we probably
211          * added.  We take into account the first and second order
212          * deltas in order to make our estimate.
213          */
214         delta = time - state->last_time;
215         state->last_time = time;
216
217         delta2 = delta - state->last_delta;
218         state->last_delta = delta;
219
220         if (delta < 0) delta = -delta;
221         if (delta2 < 0) delta2 = -delta2;
222         delta = MIN(delta, delta2) >> 1;
223         for (nbits = 0; delta; nbits++)
224                 delta >>= 1;
225
226         r->entropy_count += nbits;
227         
228         /* Prevent overflow */
229         if (r->entropy_count > POOLBITS)
230                 r->entropy_count = POOLBITS;
231
232         if (r->entropy_count >= 8)
233                 selwakeup(&random_state.rsel);
234 }
235
236 void
237 add_keyboard_randomness(u_char scancode)
238 {
239         add_timer_randomness(&random_state, &keyboard_timer_state, scancode);
240 }
241
242 void
243 add_interrupt_randomness(void *vsc)
244 {
245         int intr;
246         struct random_softc *sc = vsc;
247
248         (sc->sc_handler)(sc->sc_arg);
249         intr = sc->sc_intr;
250         add_timer_randomness(&random_state, &irq_timer_state[intr], intr);
251 }
252
253 #ifdef notused
254 void
255 add_blkdev_randomness(int major)
256 {
257         if (major >= MAX_BLKDEV)
258                 return;
259
260         add_timer_randomness(&random_state, &blkdev_timer_state[major],
261                              0x200+major);
262 }
263 #endif /* notused */
264
265 #if POOLWORDS % 16
266 #error extract_entropy() assumes that POOLWORDS is a multiple of 16 words.
267 #endif
268 /*
269  * This function extracts randomness from the "entropy pool", and
270  * returns it in a buffer.  This function computes how many remaining
271  * bits of entropy are left in the pool, but it does not restrict the
272  * number of bytes that are actually obtained.
273  */
274 static __inline int
275 extract_entropy(struct random_bucket *r, char *buf, int nbytes)
276 {
277         int ret, i;
278         u_int32_t tmp[4];
279         
280         add_timer_randomness(r, &extract_timer_state, nbytes);
281         
282         /* Redundant, but just in case... */
283         if (r->entropy_count > POOLBITS) 
284                 r->entropy_count = POOLBITS;
285         /* Why is this here?  Left in from Ted Ts'o.  Perhaps to limit time. */
286         if (nbytes > 32768)
287                 nbytes = 32768;
288
289         ret = nbytes;
290         if (r->entropy_count / 8 >= nbytes)
291                 r->entropy_count -= nbytes*8;
292         else
293                 r->entropy_count = 0;
294
295         while (nbytes) {
296                 /* Hash the pool to get the output */
297                 tmp[0] = 0x67452301;
298                 tmp[1] = 0xefcdab89;
299                 tmp[2] = 0x98badcfe;
300                 tmp[3] = 0x10325476;
301                 for (i = 0; i < POOLWORDS; i += 16)
302                         MD5Transform(tmp, (char *)(r->pool+i));
303                 /* Modify pool so next hash will produce different results */
304                 add_entropy_word(r, tmp[0]);
305                 add_entropy_word(r, tmp[1]);
306                 add_entropy_word(r, tmp[2]);
307                 add_entropy_word(r, tmp[3]);
308                 /*
309                  * Run the MD5 Transform one more time, since we want
310                  * to add at least minimal obscuring of the inputs to
311                  * add_entropy_word().  --- TYT
312                  */
313                 MD5Transform(tmp, (char *)(r->pool));
314                 
315                 /* Copy data to destination buffer */
316                 i = MIN(nbytes, 16);
317                 bcopy(tmp, buf, i);
318                 nbytes -= i;
319                 buf += i;
320         }
321
322         /* Wipe data from memory */
323         bzero(tmp, sizeof(tmp));
324         
325         return ret;
326 }
327
328 #ifdef notused /* XXX NOT the exported kernel interface */
329 /*
330  * This function is the exported kernel interface.  It returns some
331  * number of good random numbers, suitable for seeding TCP sequence
332  * numbers, etc.
333  */
334 void
335 get_random_bytes(void *buf, u_int nbytes)
336 {
337         extract_entropy(&random_state, (char *) buf, nbytes);
338 }
339 #endif /* notused */
340
341 u_int
342 read_random(void *buf, u_int nbytes)
343 {
344         if ((nbytes * 8) > random_state.entropy_count)
345                 nbytes = random_state.entropy_count / 8;
346         
347         return extract_entropy(&random_state, (char *)buf, nbytes);
348 }
349
350 u_int
351 read_random_unlimited(void *buf, u_int nbytes)
352 {
353         return extract_entropy(&random_state, (char *)buf, nbytes);
354 }
355
356 #ifdef notused
357 u_int
358 write_random(const char *buf, u_int nbytes)
359 {
360         u_int i;
361         u_int32_t word, *p;
362
363         for (i = nbytes, p = (u_int32_t *)buf;
364              i >= sizeof(u_int32_t);
365              i-= sizeof(u_int32_t), p++)
366                 add_entropy_word(&random_state, *p);
367         if (i) {
368                 word = 0;
369                 bcopy(p, &word, i);
370                 add_entropy_word(&random_state, word);
371         }
372         return nbytes;
373 }
374 #endif /* notused */
375
376 void
377 add_true_randomness(int val)
378 {
379         add_entropy_word(&random_state, val);
380         random_state.entropy_count += 8*sizeof (val);
381         if (random_state.entropy_count > POOLBITS)
382                 random_state.entropy_count = POOLBITS;
383         selwakeup(&random_state.rsel);
384 }
385
386 int
387 random_poll(dev_t dev, int events, struct thread *td)
388 {
389         int s;
390         int revents = 0;
391
392         s = splhigh();
393         if (events & (POLLIN | POLLRDNORM)) {
394                 if (random_state.entropy_count >= 8)
395                         revents |= events & (POLLIN | POLLRDNORM);
396                 else
397                         selrecord(td, &random_state.rsel);
398         }
399         splx(s);
400         if (events & (POLLOUT | POLLWRNORM))
401                 revents |= events & (POLLOUT | POLLWRNORM);     /* heh */
402
403         return (revents);
404 }
405