1/* 2 * Physically random numbers (very nearly uniform) 3 * D. P. Mitchell 4 * Modified by Matt Blaze 7/95 5 */ 6/* 7 * The authors of this software are Don Mitchell and Matt Blaze. 8 * Copyright (c) 1995 by AT&T. 9 * Permission to use, copy, and modify this software without fee 10 * is hereby granted, provided that this entire notice is included in 11 * all copies of any software which is or includes a copy or 12 * modification of this software and in all copies of the supporting 13 * documentation for such software. 14 * 15 * This software may be subject to United States export controls. 16 * 17 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED 18 * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY 19 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY 20 * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. 21 */ 22 23/* 24 * WARNING: depending on the particular platform, raw_truerand() 25 * output may be biased or correlated. In general, you can expect 26 * about 16 bits of "pseudo-entropy" out of each 32 bit word returned 27 * by truerand(), but it may not be uniformly diffused. You should 28 * raw_therefore run the output through some post-whitening function 29 * (like MD5 or DES or whatever) before using it to generate key 30 * material. (RSAREF's random package does this for you when you feed 31 * raw_truerand() bits to the seed input function.) 32 * 33 * The application interface, for 8, 16, and 32 bit properly "whitened" 34 * random numbers, can be found in trand8(), trand16(), and trand32(). 35 * Use those instead of calling raw_truerand() directly. 36 * 37 * The basic idea here is that between clock "skew" and various 38 * hard-to-predict OS event arrivals, counting a tight loop will yield 39 * a little (maybe a third of a bit or so) of "good" randomness per 40 * interval clock tick. This seems to work well even on unloaded 41 * machines. If there is a human operator at the machine, you should 42 * augment truerand with other measure, like keyboard event timing. 43 * On server machines (e.g., when you need to generate a 44 * Diffie-Hellman secret) truerand alone may be good enough. 45 * 46 * Test these assumptions on your own platform before fielding a 47 * system based on this software or these techniques. 48 * 49 * This software seems to work well (at 10 or so bits per 50 * raw_truerand() call) on a Sun Sparc-20 under SunOS 4.1.3 and on a 51 * P100 under BSDI 2.0. You're on your own elsewhere. 52 * 53 */ 54 55#include "t_defines.h" 56 57#include <signal.h> 58#include <setjmp.h> 59#include <sys/time.h> 60#include <math.h> 61#include <stdio.h> 62 63#ifdef OLD_TRUERAND 64static jmp_buf env; 65#endif 66static unsigned volatile count 67#ifndef OLD_TRUERAND 68 , done = 0 69#endif 70; 71 72static unsigned ocount; 73static unsigned buffer; 74 75static void 76tick() 77{ 78 struct itimerval it, oit; 79 80 it.it_interval.tv_sec = 0; 81 it.it_interval.tv_usec = 0; 82 it.it_value.tv_sec = 0; 83 it.it_value.tv_usec = 16665; 84 if (setitimer(ITIMER_REAL, &it, &oit) < 0) 85 perror("tick"); 86} 87 88static void 89interrupt() 90{ 91 if (count) { 92#ifdef OLD_TRUERAND 93 longjmp(env, 1); 94#else 95 ++done; 96 return; 97#endif 98 } 99 100 (void) signal(SIGALRM, interrupt); 101 tick(); 102} 103 104static unsigned long 105roulette() 106{ 107#ifdef OLD_TRUERAND 108 if (setjmp(env)) { 109 count ^= (count>>3) ^ (count>>6) ^ ocount; 110 count &= 0x7; 111 ocount=count; 112 buffer = (buffer<<3) ^ count; 113 return buffer; 114 } 115#else 116 done = 0; 117#endif 118 (void) signal(SIGALRM, interrupt); 119 count = 0; 120 tick(); 121#ifdef OLD_TRUERAND 122 for (;;) 123#else 124 while(done == 0) 125#endif 126 count++; /* about 1 MHz on VAX 11/780 */ 127#ifndef OLD_TRUERAND 128 count ^= (count>>3) ^ (count>>6) ^ ocount; 129 count &= 0x7; 130 ocount=count; 131 buffer = (buffer<<3) ^ count; 132 return buffer; 133#endif 134} 135 136unsigned long 137raw_truerand() 138{ 139 count=0; 140 (void) roulette(); 141 (void) roulette(); 142 (void) roulette(); 143 (void) roulette(); 144 (void) roulette(); 145 (void) roulette(); 146 (void) roulette(); 147 (void) roulette(); 148 (void) roulette(); 149 (void) roulette(); 150 return roulette(); 151} 152