| /* |
| * Physically random numbers (very nearly uniform) |
| * D. P. Mitchell |
| * Modified by Matt Blaze 7/95 |
| */ |
| /* |
| * The authors of this software are Don Mitchell and Matt Blaze. |
| * Copyright (c) 1995 by AT&T. |
| * Permission to use, copy, and modify this software without fee |
| * is hereby granted, provided that this entire notice is included in |
| * all copies of any software which is or includes a copy or |
| * modification of this software and in all copies of the supporting |
| * documentation for such software. |
| * |
| * This software may be subject to United States export controls. |
| * |
| * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED |
| * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY |
| * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY |
| * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. |
| */ |
| |
| /* |
| * WARNING: depending on the particular platform, raw_truerand() |
| * output may be biased or correlated. In general, you can expect |
| * about 16 bits of "pseudo-entropy" out of each 32 bit word returned |
| * by truerand(), but it may not be uniformly diffused. You should |
| * raw_therefore run the output through some post-whitening function |
| * (like MD5 or DES or whatever) before using it to generate key |
| * material. (RSAREF's random package does this for you when you feed |
| * raw_truerand() bits to the seed input function.) |
| * |
| * The application interface, for 8, 16, and 32 bit properly "whitened" |
| * random numbers, can be found in trand8(), trand16(), and trand32(). |
| * Use those instead of calling raw_truerand() directly. |
| * |
| * The basic idea here is that between clock "skew" and various |
| * hard-to-predict OS event arrivals, counting a tight loop will yield |
| * a little (maybe a third of a bit or so) of "good" randomness per |
| * interval clock tick. This seems to work well even on unloaded |
| * machines. If there is a human operator at the machine, you should |
| * augment truerand with other measure, like keyboard event timing. |
| * On server machines (e.g., when you need to generate a |
| * Diffie-Hellman secret) truerand alone may be good enough. |
| * |
| * Test these assumptions on your own platform before fielding a |
| * system based on this software or these techniques. |
| * |
| * This software seems to work well (at 10 or so bits per |
| * raw_truerand() call) on a Sun Sparc-20 under SunOS 4.1.3 and on a |
| * P100 under BSDI 2.0. You're on your own elsewhere. |
| * |
| */ |
| |
| #include "t_defines.h" |
| |
| #ifdef WIN32 |
| |
| # ifdef CRYPTOLIB |
| |
| /* Cryptolib contains its own truerand() on both UNIX and Windows. */ |
| /* Only use cryptolib's truerand under Windows */ |
| |
| # include "libcrypt.h" |
| |
| unsigned long |
| raw_truerand() |
| { |
| return truerand(); |
| } |
| |
| # else /* !CRYPTOLIB && WIN32 */ |
| |
| #include <wtypes.h> |
| #include <winbase.h> |
| #include <windef.h> |
| #include <winnt.h> |
| #include <winuser.h> |
| #include <process.h> |
| |
| volatile unsigned long count, ocount, randbuf; |
| volatile int dontstop; |
| char outbuf[1024], *bufp; |
| |
| static void counter() { |
| while (dontstop) |
| count++; |
| _endthread(); |
| } |
| |
| |
| static unsigned long roulette() { |
| unsigned long thread; |
| |
| count = 0; |
| dontstop= 1; |
| while ((thread = _beginthread((void *)counter, 1024, NULL)) < 0) |
| ; |
| |
| Sleep(16); |
| dontstop = 0; |
| Sleep(1); |
| |
| count ^= (count>>3) ^ (count>>6) ^ (ocount); |
| count &= 0x7; |
| ocount = count; |
| randbuf = (randbuf<<3) ^ count; |
| return randbuf; |
| } |
| |
| |
| unsigned long |
| raw_truerand() { |
| |
| roulette(); |
| roulette(); |
| roulette(); |
| roulette(); |
| roulette(); |
| roulette(); |
| roulette(); |
| roulette(); |
| roulette(); |
| roulette(); |
| return roulette(); |
| } |
| |
| # endif /* CRYPTOLIB */ |
| |
| #else /* !WIN32 */ |
| |
| #include <signal.h> |
| #include <setjmp.h> |
| #include <sys/time.h> |
| #include <math.h> |
| #include <stdio.h> |
| |
| #ifdef OLD_TRUERAND |
| static jmp_buf env; |
| #endif |
| static unsigned volatile count |
| #ifndef OLD_TRUERAND |
| , done = 0 |
| #endif |
| ; |
| |
| static unsigned ocount; |
| static unsigned buffer; |
| |
| static void |
| tick() |
| { |
| struct itimerval it, oit; |
| |
| it.it_interval.tv_sec = 0; |
| it.it_interval.tv_usec = 0; |
| it.it_value.tv_sec = 0; |
| it.it_value.tv_usec = 16665; |
| if (setitimer(ITIMER_REAL, &it, &oit) < 0) |
| perror("tick"); |
| } |
| |
| static void |
| interrupt() |
| { |
| if (count) { |
| #ifdef OLD_TRUERAND |
| longjmp(env, 1); |
| #else |
| ++done; |
| return; |
| #endif |
| } |
| |
| (void) signal(SIGALRM, interrupt); |
| tick(); |
| } |
| |
| static unsigned long |
| roulette() |
| { |
| #ifdef OLD_TRUERAND |
| if (setjmp(env)) { |
| count ^= (count>>3) ^ (count>>6) ^ ocount; |
| count &= 0x7; |
| ocount=count; |
| buffer = (buffer<<3) ^ count; |
| return buffer; |
| } |
| #else |
| done = 0; |
| #endif |
| (void) signal(SIGALRM, interrupt); |
| count = 0; |
| tick(); |
| #ifdef OLD_TRUERAND |
| for (;;) |
| #else |
| while(done == 0) |
| #endif |
| count++; /* about 1 MHz on VAX 11/780 */ |
| #ifndef OLD_TRUERAND |
| count ^= (count>>3) ^ (count>>6) ^ ocount; |
| count &= 0x7; |
| ocount=count; |
| buffer = (buffer<<3) ^ count; |
| return buffer; |
| #endif |
| } |
| |
| unsigned long |
| raw_truerand() |
| { |
| count=0; |
| (void) roulette(); |
| (void) roulette(); |
| (void) roulette(); |
| (void) roulette(); |
| (void) roulette(); |
| (void) roulette(); |
| (void) roulette(); |
| (void) roulette(); |
| (void) roulette(); |
| (void) roulette(); |
| return roulette(); |
| } |
| |
| int |
| raw_n_truerand(n) |
| int n; |
| { |
| int slop, v; |
| |
| slop = 0x7FFFFFFF % n; |
| do { |
| v = raw_truerand() >> 1; |
| } while (v <= slop); |
| return v % n; |
| } |
| |
| #endif /* !CRYPTOLIB || !WIN32 */ |