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