Index: sys/alpha/alpha/machdep.c =================================================================== RCS file: /home/ncvs/src/sys/alpha/alpha/machdep.c,v retrieving revision 1.68 diff -u -r1.68 machdep.c --- sys/alpha/alpha/machdep.c 2000/02/29 08:48:08 1.68 +++ sys/alpha/alpha/machdep.c 2000/05/24 05:47:57 @@ -112,6 +112,7 @@ #include #include #include +#include #include #include #include @@ -996,6 +997,11 @@ proc0.p_md.md_tf = (struct trapframe *)proc0paddr->u_pcb.pcb_hw.apcb_ksp; + /* + * Initialise entropy pool. + */ + rand_initialize(); + /* * Look at arguments passed to us and compute boothowto. */ @@ -2110,14 +2116,4 @@ } p->p_md.md_flags |= MDP_FPUSED; -} - -/* - * dummy version of read_random() until the random driver is ported. - */ -int read_random __P((void)); -int -read_random(void) -{ - return (0); } Index: sys/alpha/alpha/mem.c =================================================================== RCS file: /home/ncvs/src/sys/alpha/alpha/mem.c,v retrieving revision 1.19 diff -u -r1.19 mem.c --- sys/alpha/alpha/mem.c 1999/11/07 12:01:27 1.19 +++ sys/alpha/alpha/mem.c 2000/05/24 05:43:52 @@ -55,9 +55,10 @@ #include #include #include +#include +#include #include -/* #include */ #include #ifdef PERFMON #include @@ -67,7 +68,7 @@ #include #include -static caddr_t zeropage; +static caddr_t zbuf; static d_open_t mmopen; static d_close_t mmclose; @@ -94,7 +95,19 @@ /* bmaj */ -1 }; +/* + XXX the below should be used. However there is too much "16" + hardcodeing in kern_random.c right now. -- obrien +#if NHWI > 0 +#define ICU_LEN (NHWI) +#else +#define ICU_LEN (NSWI) +#endif +*/ +#define ICU_LEN 16 +static struct random_softc random_softc[ICU_LEN]; +static int random_ioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); static int mmclose(dev, flags, fmt, p) @@ -151,7 +164,11 @@ register int c; register struct iovec *iov; int error = 0, rw; + u_int poolsize; + caddr_t buf; + buf = NULL; + while (uio->uio_resid > 0 && !error) { iov = uio->uio_iov; if (iov->iov_len == 0) { @@ -171,6 +188,7 @@ rw = (uio->uio_rw == UIO_READ) ? VM_PROT_READ : VM_PROT_WRITE; if ((alpha_pa_access(v) & rw) != rw) { error = EFAULT; + c = 0; break; } @@ -178,7 +196,7 @@ c = min(uio->uio_resid, (int)(PAGE_SIZE - o)); error = uiomove((caddr_t)ALPHA_PHYS_TO_K0SEG(v), c, uio); - break; + continue; /* minor device 1 is kernel memory */ case 1: { @@ -212,38 +230,92 @@ return (EFAULT); #endif error = uiomove((caddr_t)v, c, uio); - break; + continue; } /* minor device 2 is EOF/rathole */ case 2: - if (uio->uio_rw == UIO_WRITE) - uio->uio_resid = 0; - return (0); + if (uio->uio_rw == UIO_READ) + return (0); + c = iov->iov_len; + break; + +/* minor device 3 (/dev/random) is source of filth on read, rathole on write */ + case 3: + if (uio->uio_rw == UIO_WRITE) { + c = iov->iov_len; + break; + } + if (buf == NULL) + buf = (caddr_t) + malloc(PAGE_SIZE, M_TEMP, M_WAITOK); + c = min(iov->iov_len, PAGE_SIZE); + poolsize = read_random(buf, c); + if (poolsize == 0) { + if (buf) + free(buf, M_TEMP); + return (0); + } + c = min(c, poolsize); + error = uiomove(buf, c, uio); + continue; + +/* minor device 4 (/dev/urandom) is source of muck on read, rathole on write */ + case 4: + if (uio->uio_rw == UIO_WRITE) { + c = iov->iov_len; + break; + } + if (CURSIG(curproc) != 0) { + /* + * Use tsleep() to get the error code right. + * It should return immediately. + */ + error = tsleep(&random_softc[0], + PZERO | PCATCH, "urand", 1); + if (error != 0 && error != EWOULDBLOCK) + continue; + } + if (buf == NULL) + buf = (caddr_t) + malloc(PAGE_SIZE, M_TEMP, M_WAITOK); + c = min(iov->iov_len, PAGE_SIZE); + poolsize = read_random_unlimited(buf, c); + c = min(c, poolsize); + error = uiomove(buf, c, uio); + continue; /* minor device 12 (/dev/zero) is source of nulls on read, rathole on write */ case 12: if (uio->uio_rw == UIO_WRITE) { - uio->uio_resid = 0; - return (0); + c = iov->iov_len; + break; } /* * On the first call, allocate and zero a page * of memory for use with /dev/zero. */ - if (zeropage == NULL) { - zeropage = (caddr_t) + if (zbuf == NULL) { + zbuf = (caddr_t) malloc(PAGE_SIZE, M_TEMP, M_WAITOK); - bzero(zeropage, PAGE_SIZE); + bzero(zbuf, PAGE_SIZE); } c = min(iov->iov_len, PAGE_SIZE); - error = uiomove(zeropage, c, uio); - break; + error = uiomove(zbuf, c, uio); + continue; default: return (ENXIO); } + if (error) + break; + iov->iov_base += c; + iov->iov_len -= c; + uio->uio_offset += c; + uio->uio_resid -= c; } + if (buf) + free(buf, M_TEMP); return (error); } @@ -293,7 +365,7 @@ switch(minor(dev)) { case 3: case 4: - break; + return random_ioctl(dev, cmd, cmdarg, flags, p); #ifdef PERFMON case 32: @@ -399,5 +471,15 @@ #endif /* PERFMON */ } -SYSINIT(memdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,mem_drvinit,NULL) +static int +random_ioctl(dev, cmd, data, flags, p) + dev_t dev; + u_long cmd; + caddr_t data; + int flags; + struct proc *p; +{ + return (0); +} +SYSINIT(memdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,mem_drvinit,NULL) Index: sys/alpha/include/types.h =================================================================== RCS file: /home/ncvs/src/sys/alpha/include/types.h,v retrieving revision 1.11 diff -u -r1.11 types.h --- sys/alpha/include/types.h 1999/12/29 04:28:00 1.11 +++ sys/alpha/include/types.h 2000/05/24 04:43:30 @@ -67,7 +67,7 @@ /* Interrupt mask (spl, xxx_imask, etc) */ typedef __uint32_t intrmask_t; -/* Interrupt handler function type - arg should be "void *" one day */ -typedef void inthand2_t(int _unit); +/* Interrupt handler function type */ +typedef void inthand2_t(void *); #endif /* _MACHTYPES_H_ */ Index: sys/conf/files =================================================================== RCS file: /home/ncvs/src/sys/conf/files,v retrieving revision 1.340 diff -u -r1.340 files --- sys/conf/files 2000/03/08 16:17:06 1.340 +++ sys/conf/files 2000/05/24 04:36:43 @@ -423,6 +423,7 @@ kern/kern_physio.c standard kern/kern_proc.c standard kern/kern_prot.c standard +kern/kern_random.c standard kern/kern_resource.c standard kern/kern_shutdown.c standard kern/kern_sig.c standard Index: sys/conf/files.i386 =================================================================== RCS file: /home/ncvs/src/sys/conf/files.i386,v retrieving revision 1.307 diff -u -r1.307 files.i386 --- sys/conf/files.i386 2000/02/21 02:10:01 1.307 +++ sys/conf/files.i386 2000/05/24 04:37:37 @@ -240,7 +240,6 @@ i386/isa/pcvt/pcvt_sup.c optional vt i386/isa/pcvt/pcvt_vtf.c optional vt i386/isa/prof_machdep.c optional profiling-routine -i386/isa/random_machdep.c standard i386/isa/rc.c optional rc i386/isa/rp.c optional rp i386/isa/scd.c optional scd Index: sys/conf/files.pc98 =================================================================== RCS file: /home/ncvs/src/sys/conf/files.pc98,v retrieving revision 1.140 diff -u -r1.140 files.pc98 --- sys/conf/files.pc98 2000/03/01 08:50:05 1.140 +++ sys/conf/files.pc98 2000/05/24 04:37:34 @@ -228,7 +228,6 @@ i386/isa/pcvt/pcvt_vtf.c optional vt pc98/pc98/ppc.c optional ppc i386/isa/prof_machdep.c optional profiling-routine -i386/isa/random_machdep.c standard i386/isa/rc.c optional rc i386/isa/rp.c optional rp i386/isa/scd.c optional scd Index: sys/i386/include/random.h =================================================================== RCS file: /home/ncvs/src/sys/i386/include/Attic/random.h,v retrieving revision 1.18 diff -u -r1.18 random.h --- sys/i386/include/random.h 1999/12/29 04:33:06 1.18 +++ sys/i386/include/random.h 2000/05/24 04:33:20 @@ -1,90 +0,0 @@ -/* - * random.h -- A strong random number generator - * - * $FreeBSD: src/sys/i386/include/random.h,v 1.18 1999/12/29 04:33:06 peter Exp $ - * - * Version 0.95, last modified 18-Oct-95 - * - * Copyright Theodore Ts'o, 1994, 1995. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -/* - * Many kernel routines will have a use for good random numbers, - * for example, for truely random TCP sequence numbers, which prevent - * certain forms of TCP spoofing attacks. - * - */ - -#ifndef _MACHINE_RANDOM_H_ -#define _MACHINE_RANDOM_H_ - -#include - -#define MEM_SETIRQ _IOW('r', 1, u_int16_t) /* set interrupt */ -#define MEM_CLEARIRQ _IOW('r', 2, u_int16_t) /* clear interrupt */ -#define MEM_RETURNIRQ _IOR('r', 3, u_int16_t) /* return interrupt */ - -#ifdef _KERNEL - -/* Type of the cookie passed to add_interrupt_randomness. */ - -struct random_softc { - inthand2_t *sc_handler; - void *sc_arg; - int sc_intr; -}; - -/* Exported functions */ - -void rand_initialize(void); -void add_keyboard_randomness(u_char scancode); -inthand2_t add_interrupt_randomness; -#ifdef notused -void add_blkdev_randomness(int major); -#endif - -#ifdef notused -void get_random_bytes(void *buf, u_int nbytes); -#endif -u_int read_random(void *buf, u_int size); -u_int read_random_unlimited(void *buf, u_int size); -#ifdef notused -u_int write_random(const char *buf, u_int nbytes); -#endif -int random_poll(dev_t dev, int events, struct proc *p); - -#endif /* _KERNEL */ - -#endif /* !_MACHINE_RANDOM_H_ */ Index: sys/i386/isa/random_machdep.c =================================================================== RCS file: /home/ncvs/src/sys/i386/isa/Attic/random_machdep.c,v retrieving revision 1.33 diff -u -r1.33 random_machdep.c --- sys/i386/isa/random_machdep.c 1999/10/11 15:00:09 1.33 +++ sys/i386/isa/random_machdep.c 2000/05/24 04:33:11 @@ -1,378 +0,0 @@ -/* - * random_machdep.c -- A strong random number generator - * - * $FreeBSD: src/sys/i386/isa/random_machdep.c,v 1.33 1999/10/11 15:00:09 peter Exp $ - * - * Version 0.95, last modified 18-Oct-95 - * - * Copyright Theodore Ts'o, 1994, 1995. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include - -#define MAX_BLKDEV 4 - -/* - * The pool is stirred with a primitive polynomial of degree 128 - * over GF(2), namely x^128 + x^99 + x^59 + x^31 + x^9 + x^7 + 1. - * For a pool of size 64, try x^64+x^62+x^38+x^10+x^6+x+1. - */ -#define POOLWORDS 128 /* Power of 2 - note that this is 32-bit words */ -#define POOLBITS (POOLWORDS*32) - -#if POOLWORDS == 128 -#define TAP1 99 /* The polynomial taps */ -#define TAP2 59 -#define TAP3 31 -#define TAP4 9 -#define TAP5 7 -#elif POOLWORDS == 64 -#define TAP1 62 /* The polynomial taps */ -#define TAP2 38 -#define TAP3 10 -#define TAP4 6 -#define TAP5 1 -#else -#error No primitive polynomial available for chosen POOLWORDS -#endif - -#define WRITEBUFFER 512 /* size in bytes */ - -/* There is actually only one of these, globally. */ -struct random_bucket { - u_int add_ptr; - u_int entropy_count; - int input_rotate; - u_int32_t *pool; - struct selinfo rsel; -}; - -/* There is one of these per entropy source */ -struct timer_rand_state { - u_long last_time; - int last_delta; - int nbits; -}; - -static struct random_bucket random_state; -static u_int32_t random_pool[POOLWORDS]; -static struct timer_rand_state keyboard_timer_state; -static struct timer_rand_state extract_timer_state; -static struct timer_rand_state irq_timer_state[ICU_LEN]; -#ifdef notyet -static struct timer_rand_state blkdev_timer_state[MAX_BLKDEV]; -#endif -static struct wait_queue *random_wait; - -#ifndef MIN -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) -#endif - -void -rand_initialize(void) -{ - random_state.add_ptr = 0; - random_state.entropy_count = 0; - random_state.pool = random_pool; - random_wait = NULL; - random_state.rsel.si_flags = 0; - random_state.rsel.si_pid = 0; -} - -/* - * This function adds an int into the entropy "pool". It does not - * update the entropy estimate. The caller must do this if appropriate. - * - * The pool is stirred with a primitive polynomial of degree 128 - * over GF(2), namely x^128 + x^99 + x^59 + x^31 + x^9 + x^7 + 1. - * For a pool of size 64, try x^64+x^62+x^38+x^10+x^6+x+1. - * - * We rotate the input word by a changing number of bits, to help - * assure that all bits in the entropy get toggled. Otherwise, if we - * consistently feed the entropy pool small numbers (like ticks and - * scancodes, for example), the upper bits of the entropy pool don't - * get affected. --- TYT, 10/11/95 - */ -static __inline void -add_entropy_word(struct random_bucket *r, const u_int32_t input) -{ - u_int i; - u_int32_t w; - - w = (input << r->input_rotate) | (input >> (32 - r->input_rotate)); - i = r->add_ptr = (r->add_ptr - 1) & (POOLWORDS-1); - if (i) - r->input_rotate = (r->input_rotate + 7) & 31; - else - /* - * At the beginning of the pool, add an extra 7 bits - * rotation, so that successive passes spread the - * input bits across the pool evenly. - */ - r->input_rotate = (r->input_rotate + 14) & 31; - - /* XOR in the various taps */ - w ^= r->pool[(i+TAP1)&(POOLWORDS-1)]; - w ^= r->pool[(i+TAP2)&(POOLWORDS-1)]; - w ^= r->pool[(i+TAP3)&(POOLWORDS-1)]; - w ^= r->pool[(i+TAP4)&(POOLWORDS-1)]; - w ^= r->pool[(i+TAP5)&(POOLWORDS-1)]; - w ^= r->pool[i]; - /* Rotate w left 1 bit (stolen from SHA) and store */ - r->pool[i] = (w << 1) | (w >> 31); -} - -/* - * This function adds entropy to the entropy "pool" by using timing - * delays. It uses the timer_rand_state structure to make an estimate - * of how any bits of entropy this call has added to the pool. - * - * The number "num" is also added to the pool - it should somehow describe - * the type of event which just happened. This is currently 0-255 for - * keyboard scan codes, and 256 upwards for interrupts. - * On the i386, this is assumed to be at most 16 bits, and the high bits - * are used for a high-resolution timer. - */ -static void -add_timer_randomness(struct random_bucket *r, struct timer_rand_state *state, - u_int num) -{ - int delta, delta2; - u_int nbits; - u_int32_t time; - - num ^= timecounter->tc_get_timecount(timecounter) << 16; - r->entropy_count += 2; - - time = ticks; - - add_entropy_word(r, (u_int32_t) num); - add_entropy_word(r, time); - - /* - * Calculate number of bits of randomness we probably - * added. We take into account the first and second order - * deltas in order to make our estimate. - */ - delta = time - state->last_time; - state->last_time = time; - - delta2 = delta - state->last_delta; - state->last_delta = delta; - - if (delta < 0) delta = -delta; - if (delta2 < 0) delta2 = -delta2; - delta = MIN(delta, delta2) >> 1; - for (nbits = 0; delta; nbits++) - delta >>= 1; - - r->entropy_count += nbits; - - /* Prevent overflow */ - if (r->entropy_count > POOLBITS) - r->entropy_count = POOLBITS; - - if (r->entropy_count >= 8) - selwakeup(&random_state.rsel); -} - -void -add_keyboard_randomness(u_char scancode) -{ - add_timer_randomness(&random_state, &keyboard_timer_state, scancode); -} - -void -add_interrupt_randomness(void *vsc) -{ - int intr; - struct random_softc *sc = vsc; - - (sc->sc_handler)(sc->sc_arg); - intr = sc->sc_intr; - add_timer_randomness(&random_state, &irq_timer_state[intr], intr); -} - -#ifdef notused -void -add_blkdev_randomness(int major) -{ - if (major >= MAX_BLKDEV) - return; - - add_timer_randomness(&random_state, &blkdev_timer_state[major], - 0x200+major); -} -#endif /* notused */ - -#if POOLWORDS % 16 -#error extract_entropy() assumes that POOLWORDS is a multiple of 16 words. -#endif -/* - * This function extracts randomness from the "entropy pool", and - * returns it in a buffer. This function computes how many remaining - * bits of entropy are left in the pool, but it does not restrict the - * number of bytes that are actually obtained. - */ -static __inline int -extract_entropy(struct random_bucket *r, char *buf, int nbytes) -{ - int ret, i; - u_int32_t tmp[4]; - - add_timer_randomness(r, &extract_timer_state, nbytes); - - /* Redundant, but just in case... */ - if (r->entropy_count > POOLBITS) - r->entropy_count = POOLBITS; - /* Why is this here? Left in from Ted Ts'o. Perhaps to limit time. */ - if (nbytes > 32768) - nbytes = 32768; - - ret = nbytes; - if (r->entropy_count / 8 >= nbytes) - r->entropy_count -= nbytes*8; - else - r->entropy_count = 0; - - while (nbytes) { - /* Hash the pool to get the output */ - tmp[0] = 0x67452301; - tmp[1] = 0xefcdab89; - tmp[2] = 0x98badcfe; - tmp[3] = 0x10325476; - for (i = 0; i < POOLWORDS; i += 16) - MD5Transform(tmp, (char *)(r->pool+i)); - /* Modify pool so next hash will produce different results */ - add_entropy_word(r, tmp[0]); - add_entropy_word(r, tmp[1]); - add_entropy_word(r, tmp[2]); - add_entropy_word(r, tmp[3]); - /* - * Run the MD5 Transform one more time, since we want - * to add at least minimal obscuring of the inputs to - * add_entropy_word(). --- TYT - */ - MD5Transform(tmp, (char *)(r->pool)); - - /* Copy data to destination buffer */ - i = MIN(nbytes, 16); - bcopy(tmp, buf, i); - nbytes -= i; - buf += i; - } - - /* Wipe data from memory */ - bzero(tmp, sizeof(tmp)); - - return ret; -} - -#ifdef notused /* XXX NOT the exported kernel interface */ -/* - * This function is the exported kernel interface. It returns some - * number of good random numbers, suitable for seeding TCP sequence - * numbers, etc. - */ -void -get_random_bytes(void *buf, u_int nbytes) -{ - extract_entropy(&random_state, (char *) buf, nbytes); -} -#endif /* notused */ - -u_int -read_random(void *buf, u_int nbytes) -{ - if ((nbytes * 8) > random_state.entropy_count) - nbytes = random_state.entropy_count / 8; - - return extract_entropy(&random_state, (char *)buf, nbytes); -} - -u_int -read_random_unlimited(void *buf, u_int nbytes) -{ - return extract_entropy(&random_state, (char *)buf, nbytes); -} - -#ifdef notused -u_int -write_random(const char *buf, u_int nbytes) -{ - u_int i; - u_int32_t word, *p; - - for (i = nbytes, p = (u_int32_t *)buf; - i >= sizeof(u_int32_t); - i-= sizeof(u_int32_t), p++) - add_entropy_word(&random_state, *p); - if (i) { - word = 0; - bcopy(p, &word, i); - add_entropy_word(&random_state, word); - } - return nbytes; -} -#endif /* notused */ - -int -random_poll(dev_t dev, int events, struct proc *p) -{ - int s; - int revents = 0; - - s = splhigh(); - if (events & (POLLIN | POLLRDNORM)) { - if (random_state.entropy_count >= 8) - revents |= events & (POLLIN | POLLRDNORM); - else - selrecord(p, &random_state.rsel); - } - splx(s); - if (events & (POLLOUT | POLLWRNORM)) - revents |= events & (POLLOUT | POLLWRNORM); /* heh */ - - return (revents); -} - --- /dev/null Tue May 23 22:48:55 2000 +++ sys/kern/kern_random.c Tue May 23 21:09:05 2000 @@ -0,0 +1,392 @@ +/* + * kern_random.c -- A strong random number generator + * + * $FreeBSD: src/sys/kern/kern_random.c,v 1.36.2.1 2000/05/10 02:04:49 obrien Exp $ + * + * Version 0.95, last modified 18-Oct-95 + * + * Copyright Theodore Ts'o, 1994, 1995. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __i386__ +#include +#endif +#ifdef __alpha__ +/* + XXX the below should be used. However there is too much "16" + hardcodeing in kern_random.c right now. -- obrien +#include +#if NHWI > 0 +#define ICU_LEN (NHWI) +#else +#define ICU_LEN (NSWI) +#endif +*/ +#define ICU_LEN 16 +#endif + +#define MAX_BLKDEV 4 + +/* + * The pool is stirred with a primitive polynomial of degree 128 + * over GF(2), namely x^128 + x^99 + x^59 + x^31 + x^9 + x^7 + 1. + * For a pool of size 64, try x^64+x^62+x^38+x^10+x^6+x+1. + */ +#define POOLWORDS 128 /* Power of 2 - note that this is 32-bit words */ +#define POOLBITS (POOLWORDS*32) + +#if POOLWORDS == 128 +#define TAP1 99 /* The polynomial taps */ +#define TAP2 59 +#define TAP3 31 +#define TAP4 9 +#define TAP5 7 +#elif POOLWORDS == 64 +#define TAP1 62 /* The polynomial taps */ +#define TAP2 38 +#define TAP3 10 +#define TAP4 6 +#define TAP5 1 +#else +#error No primitive polynomial available for chosen POOLWORDS +#endif + +#define WRITEBUFFER 512 /* size in bytes */ + +/* There is actually only one of these, globally. */ +struct random_bucket { + u_int add_ptr; + u_int entropy_count; + int input_rotate; + u_int32_t *pool; + struct selinfo rsel; +}; + +/* There is one of these per entropy source */ +struct timer_rand_state { + u_long last_time; + int last_delta; + int nbits; +}; + +static struct random_bucket random_state; +static u_int32_t random_pool[POOLWORDS]; +static struct timer_rand_state keyboard_timer_state; +static struct timer_rand_state extract_timer_state; +static struct timer_rand_state irq_timer_state[ICU_LEN]; +#ifdef notyet +static struct timer_rand_state blkdev_timer_state[MAX_BLKDEV]; +#endif +static struct wait_queue *random_wait; + +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +void +rand_initialize(void) +{ + random_state.add_ptr = 0; + random_state.entropy_count = 0; + random_state.pool = random_pool; + random_wait = NULL; + random_state.rsel.si_flags = 0; + random_state.rsel.si_pid = 0; +} + +/* + * This function adds an int into the entropy "pool". It does not + * update the entropy estimate. The caller must do this if appropriate. + * + * The pool is stirred with a primitive polynomial of degree 128 + * over GF(2), namely x^128 + x^99 + x^59 + x^31 + x^9 + x^7 + 1. + * For a pool of size 64, try x^64+x^62+x^38+x^10+x^6+x+1. + * + * We rotate the input word by a changing number of bits, to help + * assure that all bits in the entropy get toggled. Otherwise, if we + * consistently feed the entropy pool small numbers (like ticks and + * scancodes, for example), the upper bits of the entropy pool don't + * get affected. --- TYT, 10/11/95 + */ +static __inline void +add_entropy_word(struct random_bucket *r, const u_int32_t input) +{ + u_int i; + u_int32_t w; + + w = (input << r->input_rotate) | (input >> (32 - r->input_rotate)); + i = r->add_ptr = (r->add_ptr - 1) & (POOLWORDS-1); + if (i) + r->input_rotate = (r->input_rotate + 7) & 31; + else + /* + * At the beginning of the pool, add an extra 7 bits + * rotation, so that successive passes spread the + * input bits across the pool evenly. + */ + r->input_rotate = (r->input_rotate + 14) & 31; + + /* XOR in the various taps */ + w ^= r->pool[(i+TAP1)&(POOLWORDS-1)]; + w ^= r->pool[(i+TAP2)&(POOLWORDS-1)]; + w ^= r->pool[(i+TAP3)&(POOLWORDS-1)]; + w ^= r->pool[(i+TAP4)&(POOLWORDS-1)]; + w ^= r->pool[(i+TAP5)&(POOLWORDS-1)]; + w ^= r->pool[i]; + /* Rotate w left 1 bit (stolen from SHA) and store */ + r->pool[i] = (w << 1) | (w >> 31); +} + +/* + * This function adds entropy to the entropy "pool" by using timing + * delays. It uses the timer_rand_state structure to make an estimate + * of how any bits of entropy this call has added to the pool. + * + * The number "num" is also added to the pool - it should somehow describe + * the type of event which just happened. This is currently 0-255 for + * keyboard scan codes, and 256 upwards for interrupts. + * On the i386, this is assumed to be at most 16 bits, and the high bits + * are used for a high-resolution timer. + */ +static void +add_timer_randomness(struct random_bucket *r, struct timer_rand_state *state, + u_int num) +{ + int delta, delta2; + u_int nbits; + u_int32_t time; + + num ^= timecounter->tc_get_timecount(timecounter) << 16; + r->entropy_count += 2; + + time = ticks; + + add_entropy_word(r, (u_int32_t) num); + add_entropy_word(r, time); + + /* + * Calculate number of bits of randomness we probably + * added. We take into account the first and second order + * deltas in order to make our estimate. + */ + delta = time - state->last_time; + state->last_time = time; + + delta2 = delta - state->last_delta; + state->last_delta = delta; + + if (delta < 0) delta = -delta; + if (delta2 < 0) delta2 = -delta2; + delta = MIN(delta, delta2) >> 1; + for (nbits = 0; delta; nbits++) + delta >>= 1; + + r->entropy_count += nbits; + + /* Prevent overflow */ + if (r->entropy_count > POOLBITS) + r->entropy_count = POOLBITS; + + if (r->entropy_count >= 8) + selwakeup(&random_state.rsel); +} + +void +add_keyboard_randomness(u_char scancode) +{ + add_timer_randomness(&random_state, &keyboard_timer_state, scancode); +} + +void +add_interrupt_randomness(void *vsc) +{ + int intr; + struct random_softc *sc = vsc; + + (sc->sc_handler)(sc->sc_arg); + intr = sc->sc_intr; + add_timer_randomness(&random_state, &irq_timer_state[intr], intr); +} + +#ifdef notused +void +add_blkdev_randomness(int major) +{ + if (major >= MAX_BLKDEV) + return; + + add_timer_randomness(&random_state, &blkdev_timer_state[major], + 0x200+major); +} +#endif /* notused */ + +#if POOLWORDS % 16 +#error extract_entropy() assumes that POOLWORDS is a multiple of 16 words. +#endif +/* + * This function extracts randomness from the "entropy pool", and + * returns it in a buffer. This function computes how many remaining + * bits of entropy are left in the pool, but it does not restrict the + * number of bytes that are actually obtained. + */ +static __inline int +extract_entropy(struct random_bucket *r, char *buf, int nbytes) +{ + int ret, i; + u_int32_t tmp[4]; + + add_timer_randomness(r, &extract_timer_state, nbytes); + + /* Redundant, but just in case... */ + if (r->entropy_count > POOLBITS) + r->entropy_count = POOLBITS; + /* Why is this here? Left in from Ted Ts'o. Perhaps to limit time. */ + if (nbytes > 32768) + nbytes = 32768; + + ret = nbytes; + if (r->entropy_count / 8 >= nbytes) + r->entropy_count -= nbytes*8; + else + r->entropy_count = 0; + + while (nbytes) { + /* Hash the pool to get the output */ + tmp[0] = 0x67452301; + tmp[1] = 0xefcdab89; + tmp[2] = 0x98badcfe; + tmp[3] = 0x10325476; + for (i = 0; i < POOLWORDS; i += 16) + MD5Transform(tmp, (char *)(r->pool+i)); + /* Modify pool so next hash will produce different results */ + add_entropy_word(r, tmp[0]); + add_entropy_word(r, tmp[1]); + add_entropy_word(r, tmp[2]); + add_entropy_word(r, tmp[3]); + /* + * Run the MD5 Transform one more time, since we want + * to add at least minimal obscuring of the inputs to + * add_entropy_word(). --- TYT + */ + MD5Transform(tmp, (char *)(r->pool)); + + /* Copy data to destination buffer */ + i = MIN(nbytes, 16); + bcopy(tmp, buf, i); + nbytes -= i; + buf += i; + } + + /* Wipe data from memory */ + bzero(tmp, sizeof(tmp)); + + return ret; +} + +#ifdef notused /* XXX NOT the exported kernel interface */ +/* + * This function is the exported kernel interface. It returns some + * number of good random numbers, suitable for seeding TCP sequence + * numbers, etc. + */ +void +get_random_bytes(void *buf, u_int nbytes) +{ + extract_entropy(&random_state, (char *) buf, nbytes); +} +#endif /* notused */ + +u_int +read_random(void *buf, u_int nbytes) +{ + if ((nbytes * 8) > random_state.entropy_count) + nbytes = random_state.entropy_count / 8; + + return extract_entropy(&random_state, (char *)buf, nbytes); +} + +u_int +read_random_unlimited(void *buf, u_int nbytes) +{ + return extract_entropy(&random_state, (char *)buf, nbytes); +} + +#ifdef notused +u_int +write_random(const char *buf, u_int nbytes) +{ + u_int i; + u_int32_t word, *p; + + for (i = nbytes, p = (u_int32_t *)buf; + i >= sizeof(u_int32_t); + i-= sizeof(u_int32_t), p++) + add_entropy_word(&random_state, *p); + if (i) { + word = 0; + bcopy(p, &word, i); + add_entropy_word(&random_state, word); + } + return nbytes; +} +#endif /* notused */ + +int +random_poll(dev_t dev, int events, struct proc *p) +{ + int s; + int revents = 0; + + s = splhigh(); + if (events & (POLLIN | POLLRDNORM)) { + if (random_state.entropy_count >= 8) + revents |= events & (POLLIN | POLLRDNORM); + else + selrecord(p, &random_state.rsel); + } + splx(s); + if (events & (POLLOUT | POLLWRNORM)) + revents |= events & (POLLOUT | POLLWRNORM); /* heh */ + + return (revents); +} + --- /dev/null Tue May 23 22:48:55 2000 +++ sys/sys/random.h Tue May 23 21:11:04 2000 @@ -0,0 +1,91 @@ +/* + * random.h -- A strong random number generator + * + * $FreeBSD: src/sys/sys/random.h,v 1.19.2.1 2000/05/10 02:04:52 obrien Exp $ + * + * Version 0.95, last modified 18-Oct-95 + * + * Copyright Theodore Ts'o, 1994, 1995. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * Many kernel routines will have a use for good random numbers, + * for example, for truely random TCP sequence numbers, which prevent + * certain forms of TCP spoofing attacks. + * + */ + +#ifndef _SYS_RANDOM_H_ +#define _SYS_RANDOM_H_ + +#include + +#define MEM_SETIRQ _IOW('r', 1, u_int16_t) /* set interrupt */ +#define MEM_CLEARIRQ _IOW('r', 2, u_int16_t) /* clear interrupt */ +#define MEM_RETURNIRQ _IOR('r', 3, u_int16_t) /* return interrupt */ + +#ifdef _KERNEL + +/* Type of the cookie passed to add_interrupt_randomness. */ + +struct random_softc { + inthand2_t *sc_handler; + void *sc_arg; + int sc_intr; +}; + +/* Exported functions */ + +void rand_initialize(void); +void add_keyboard_randomness(u_char scancode); +inthand2_t add_interrupt_randomness; +#ifdef notused +void add_blkdev_randomness(int major); +#endif + +#ifdef notused +void get_random_bytes(void *buf, u_int nbytes); +#endif +u_int read_random(void *buf, u_int size); +u_int read_random_unlimited(void *buf, u_int size); +#ifdef notused +u_int write_random(const char *buf, u_int nbytes); +#endif +struct proc; +int random_poll(dev_t dev, int events, struct proc *p); + +#endif /* _KERNEL */ + +#endif /* !_SYS_RANDOM_H_ */