|
|
1.1 ! root 1: /********************************************************************** ! 2: random.c - C source code for random number generation - 19 Nov 86 ! 3: (c) Copyright 1986 by Philip Zimmermann. All rights reserved. ! 4: Revised Jul 88 by PRZ and again Dec 88 by Allan Hoeltje ! 5: to use IBM PC 8253 timer0 for a faster counter. ! 6: Revised Apr 89 by PRZ to recycle random bytes. ! 7: Last revised 15 Dec 90 by PRZ. ! 8: ! 9: This code generates truly random numbers derived from a counter that is ! 10: incremented continuously while the keyboard is scanned for user input. ! 11: Every time the user touches a key, the least significant bits of the ! 12: counter are pushed on a stack. Later, this supply of random bytes can ! 13: be popped off the stack by applications requiring stochastic numbers. ! 14: Cryptographic applications require this kind of randomness. ! 15: ! 16: The only requirement to make this work is that keypress must be called ! 17: frequently, and/or getkey must be called to read the keyboard. ! 18: ! 19: Note that you can only get as many random bytes as the number of ! 20: bytes accumulated by the user touching the keyboard. ! 21: **********************************************************************/ ! 22: ! 23: #include <stdio.h> /* for putchar() and printf() */ ! 24: #include <conio.h> /* for kbhit() and getch() */ ! 25: #include "random.h" ! 26: ! 27: /* #define USEPCTIMER /* use fast hardware timer on IBM PC or AT or clone */ ! 28: /* #define DEBUG */ ! 29: ! 30: #ifdef DEBUG ! 31: #define DEBUGprintf1(x) fprintf(stderr,x) ! 32: #define DEBUGprintf2(x,y) fprintf(stderr,x,y) ! 33: #else ! 34: #define DEBUGprintf1(x) ! 35: #define DEBUGprintf2(x,y) ! 36: #endif ! 37: ! 38: ! 39: static int randseed=0; /* used only by pseudorand() function. */ ! 40: int pseudorand(void) ! 41: /* Home-grown 16-bit LCG pseudorandom generator. */ ! 42: { randseed = (randseed*31421 + 6927) & 0xffff; ! 43: return (randseed); ! 44: } /* pseudorand */ ! 45: ! 46: ! 47: int randcount = 0 ; /* # of random bytes accumulated in pool */ ! 48: static byte randpool[256] = {0} ; /* pool of truly random bytes */ ! 49: static int recyclecount = 0 ; /* # of recycled random bytes accumulated */ ! 50: static byte recyclepool[256] = {0} ; /* pool of recycled random bytes */ ! 51: static int recycleptr = 0; /* points to next byte to grab in recyclepool */ ! 52: ! 53: /* fastcounter is a free-running counter incremented in main event loop */ ! 54: static byte fastcounter = 0; /* not needed if we can use the PC timer. */ ! 55: ! 56: ! 57: #ifdef USEPCTIMER /* we will use fast hardware timer on IBM PC */ ! 58: /* #include <conio.h> /* function definitions for inp() and outp() */ ! 59: /* outp() and inp() works only for Microsoft C for IBM PC or AT */ ! 60: /* timer0 on 8253-5 on IBM PC or AT tics every .84 usec. */ ! 61: #define timer0 0x40 /* 8253 timer 0 port */ ! 62: #define timercntl 0x43 /* 8253 control register */ ! 63: #define timer0rwl 0x00 /* read lo/hi bytes of cntr 2 with latch */ ! 64: #define timer0rnl 0x30 /* read lo/hi bytes of cntr 2 w/o latch */ ! 65: ! 66: static byte latched_hitimer = 0; /* captured by keyboard ISR */ ! 67: static byte latched_lotimer = 0; /* captured by keyboard ISR */ ! 68: /* when kbisr captures timer, timer_latched is set. */ ! 69: static boolean timer_latched = FALSE; ! 70: ! 71: static void kbisr(void) /* Keyboard Interrupt Service Routine (ISR) */ ! 72: /* ! 73: kbisr should be called on the way into, or on the way out of, ! 74: or from within the DOS keyboard ISR, as long as it gets called ! 75: at the time of a keyboard interrupt. Assumes that the real ! 76: DOS keyboard ISR captures the keystroke in the normal way. ! 77: Only the hardware timer counter is captured by the kbisr routine, ! 78: leaving the actual keystroke capture to the normal DOS keyboard ISR. ! 79: We indicate that a timer capture has taken place by setting ! 80: timer_latched. ! 81: ! 82: NOTE: WE STILL NEED TO FIND A WAY to connect this subroutine with the ! 83: normal keyboard ISR, so that kbisr gets called when there's a keyboard ! 84: interrupt. ! 85: */ ! 86: { outp(timercntl,timer0rwl); ! 87: latched_lotimer = inp(timer0); ! 88: latched_hitimer = inp(timer0); ! 89: timer_latched = TRUE; ! 90: } /* kbisr */ ! 91: ! 92: static unsigned short pctimer0(void) ! 93: { ! 94: /* Reads and returns the hardware 8253 timer0 on the PC or AT ! 95: ** or clone, shifted right 1 bit. ! 96: ** ! 97: ** DO NOT SET THE HARDWARE COUNTER TO ZERO. It is already initialized ! 98: ** by the system to be used by the clock. It is set up in mode 3 ! 99: ** (square wave rate generator) and counts down by 2 from 0 (0xFFFF+1) ! 100: ** to produce an 18.2 Hz square wave. We may, however, READ the ! 101: ** lo and hi bytes without causing any problems. BUT just ! 102: ** remember that the lo byte will always be even (since it is ! 103: ** counting by two). ! 104: ** ! 105: ** Note that we can not use counter 1 since it is tied to the ! 106: ** dynamic RAM refresh hardware. Counter 2 is tied to the 8255 ! 107: ** PPI chip to do things like sound. Though it would be safe to ! 108: ** use counter 2 it is not desirable since we would have to turn ! 109: ** the speaker on in order to make the timer count! Normally one ! 110: ** sets counter 2 to mode 3 (square wave generator) to sound the ! 111: ** speaker. You can set mode 2 (pulse generator) and the speaker ! 112: ** hardly makes any sound at all, a click when you turn it on and ! 113: ** a click when you turn it off. Counter 0 should be safe if ! 114: ** we only read the counter bytes. ! 115: ** ! 116: ** WARNING: To use the hardware timer the way it really should be ! 117: ** used, we ought to capture it via a keyboard interrupt service ! 118: ** routine (ISR). Otherwise, we may experience weaknesses in randomness ! 119: ** due to harmonic relationships between the hardware counter frequency ! 120: ** and the keyboard software polling frequency. Unfortunately, this ! 121: ** implementation does not currently use keyboard interrupts to ! 122: ** capture the counter. This is not a problem if we don't use the ! 123: ** hardware counter, but instead use the software counter fastcounter. ! 124: ** Thus, the hardware counter should not be used at all, unless we ! 125: ** support it with an ISR. ! 126: */ ! 127: unsigned short t ; ! 128: /* See if timer has been latched by kbisr(). */ ! 129: if (!timer_latched) /* The timer was not already latched. */ ! 130: kbisr(); /* latch timer */ ! 131: /* return latched timer and clear latch */ ! 132: t = ( (((unsigned short) latched_hitimer) << 8) | ! 133: ((unsigned short) latched_lotimer) ! 134: ) >> 1 ; ! 135: timer_latched = FALSE; ! 136: return (t) ; ! 137: } /* pctimer0 */ ! 138: ! 139: #endif /* ifdef USEPCTIMER */ ! 140: ! 141: ! 142: void capturecounter(void) ! 143: /* Push a fast counter on the random stack. Should be called when ! 144: ** the user touches a key or clicks the mouse. ! 145: */ ! 146: { ! 147: static unsigned int accum = 0; ! 148: static byte abits = 0; /* number of accumulated bits in accum */ ! 149: ! 150: #ifdef USEPCTIMER /* we will use fast hardware timer on IBM PC */ ! 151: #define cbits 8 /* number of bits of counter to capture each time */ ! 152: fastcounter += pctimer0(); ! 153: #else /* no fast hardware timer available */ ! 154: #define cbits 4 /* number of bits of counter to capture each time */ ! 155: #endif /* ifdef USEPCTIMER */ ! 156: #define cbitsmask ((1 << cbits)-1) ! 157: ! 158: accum = (accum << cbits) | (unsigned int) (fastcounter & cbitsmask); ! 159: abits += cbits; ! 160: while (abits >= 8) ! 161: { if (randcount < sizeof(randpool)) ! 162: /* take lower byte of accum */ ! 163: randpool[randcount++] = accum; ! 164: abits -= 8; ! 165: accum >>= 8; ! 166: } ! 167: fastcounter = 0; ! 168: #undef cbitsmask ! 169: } /* capturecounter */ ! 170: ! 171: ! 172: /* Because these truly random bytes are so unwieldy to accumulate, ! 173: they can be regarded as a precious resource. Unfortunately, ! 174: cryptographic key generation algorithms may require a great many ! 175: random bytes while searching about for large random prime numbers. ! 176: Fortunately, they need not all be truly random. We only need as ! 177: many truly random bytes as there are bytes in the large prime we ! 178: are searching for. These random bytes can be recycled and modified ! 179: via pseudorandom numbers until the key is generated, without losing ! 180: any of the integrity of randomness of the final key. ! 181: */ ! 182: ! 183: ! 184: static void randstir(void) ! 185: /* Stir up the recycled random number bin, via a pseudorandom generator */ ! 186: { int i; ! 187: i = recyclecount; ! 188: while (i--) ! 189: recyclepool[i] ^= (byte) pseudorand(); ! 190: DEBUGprintf2(" Stirring %d recycled bytes. ",recyclecount); ! 191: } /* randstir */ ! 192: ! 193: ! 194: short randload(short bitcount) ! 195: /* Flushes stale recycled random bits and copies a fresh supply of raw ! 196: random bits from randpool to recyclepool. Returns actual number of ! 197: bits transferred. Formerly named randrecycle. */ ! 198: { int bytecount; ! 199: bytecount = (bitcount+7)/8; ! 200: bytecount = min(bytecount,randcount); ! 201: randflush(); /* reset recyclecount, discarding recyclepool */ ! 202: while (bytecount--) ! 203: recyclepool[recyclecount++] = randpool[--randcount]; ! 204: DEBUGprintf2("\nAllocating %d recycleable random bytes. ",recyclecount); ! 205: return(recyclecount*8); ! 206: } /* randload */ ! 207: ! 208: ! 209: void randflush(void) /* destroys pool of recycled random numbers */ ! 210: /* Ensures no sensitive data remains in memory that can be recovered later. */ ! 211: { recyclecount = sizeof (recyclepool); ! 212: while (recyclecount) ! 213: recyclepool[--recyclecount]=0; ! 214: /* recyclecount is left at 0 */ ! 215: recycleptr = 0; ! 216: } /* randflush */ ! 217: ! 218: ! 219: short randombyte(void) ! 220: /* Returns truly random byte from pool, or a pseudorandom value ! 221: ** if pool is empty. It is recommended that the caller check ! 222: ** the value of randcount before calling randombyte. ! 223: */ ! 224: { ! 225: /* First try to get a cheap recycled random byte, if there are any. */ ! 226: if (recyclecount) /* nonempty recycled pool */ ! 227: { if (++recycleptr >= recyclecount) /* ran out? */ ! 228: { recycleptr = 0; /* ran out of recycled random numbers */ ! 229: randstir(); /* stir up recycled bits */ ! 230: } ! 231: return (recyclepool[recycleptr]); ! 232: } ! 233: ! 234: /* Empty recycled pool. Try a more expensive fresh random byte. */ ! 235: if (randcount) /* nonempty random pool--return a very random number */ ! 236: return (randpool[--randcount]); ! 237: ! 238: /* Alas, fresh random pool is empty. Get a pseudorandom byte. ! 239: Pseudorandom numbers are risky for cryptographic applications. ! 240: Although we will return a pseudorandom byte in the low order byte, ! 241: indicate error by making the result negative in the high byte. ! 242: */ ! 243: /* DEBUGprintf1("\007Warning: random pool empty! "); */ ! 244: return ( (pseudorand() & 0xFF) ^ (-1) ); ! 245: } /* randombyte */ ! 246: ! 247: ! 248: static short keybuf = 0; /* used only by keypress() and getkey() */ ! 249: ! 250: boolean keypress(void) /* TRUE iff keyboard input ready */ ! 251: { /* Accumulates random numbers by timing user keystrokes. */ ! 252: static short lastkey = 0; /* used to detect autorepeat key sequences */ ! 253: static short next_to_lastkey = 0; /* allows a single repeated key */ ! 254: ! 255: #ifndef USEPCTIMER /* no fast hardware timer available */ ! 256: fastcounter++; /* used in lieu of fast hardware timer counter */ ! 257: #endif /* ifndef USEPCTIMER */ ! 258: ! 259: if (keybuf & 0x100) /* bit 8 means keybuf contains valid data */ ! 260: return( TRUE ); /* key was hit the last time thru */ ! 261: ! 262: if (kbhit() == 0) /* keyboard was not hit */ ! 263: return( FALSE ); ! 264: ! 265: keybuf = getch() | 0x100; /* set data latch bit */ ! 266: ! 267: /* Keyboard was hit. Decide whether to call capturecounter... */ ! 268: ! 269: /* Guard against typahead buffer defeating fastcounter's randomness. ! 270: ** This could be a problem for multicharacter sequences generated ! 271: ** by a function key expansion or by the user generating keystrokes ! 272: ** faster than our event loop can handle them. Only the last ! 273: ** character of a multicharacter sequence will trigger the counter ! 274: ** capture. Also, don't let the keyboard's autorepeat feature ! 275: ** produce nonrandom counter capture. However, we do allow a ! 276: ** single repeated character to trigger counter capture, because ! 277: ** many english words have double letter combinations, and it's ! 278: ** unlikely a typist would exploit the autorepeat feature to ! 279: ** type a simple double letter sequence. ! 280: */ ! 281: ! 282: if (kbhit() == 0) /* nothing in typahead buffer */ ! 283: { /* don't capture counter if key repeated */ ! 284: if (keybuf != lastkey) ! 285: capturecounter(); /* save current random number seed */ ! 286: else if (keybuf != next_to_lastkey) /* allow single repeat */ ! 287: capturecounter(); ! 288: next_to_lastkey = lastkey; ! 289: lastkey = keybuf; ! 290: } ! 291: return( TRUE ); ! 292: } /* keypress */ ! 293: ! 294: ! 295: short getkey(void) /* Returns data from keyboard (no echo). */ ! 296: { /* Also accumulates random numbers via keypress(). */ ! 297: while(! keypress() ); /* loop until key is pressed. */ ! 298: return( keybuf &= 0xff); /* clear latch bit 8 */ ! 299: } /* getkey */ ! 300: ! 301: ! 302: #define BS 8 /* ASCII backspace */ ! 303: #define CR 13 /* ASCII carriage return */ ! 304: #define LF 10 /* ASCII linefeed */ ! 305: ! 306: ! 307: int getstring(char *strbuf, int maxlen, boolean echo) ! 308: /* Gets string from user, with no control characters allowed. ! 309: Also accumulates random numbers by calling getkey(). ! 310: maxlen is max length allowed for string. ! 311: echo is TRUE iff we should echo keyboard to screen. ! 312: Returns null-terminated string in strbuf. ! 313: */ ! 314: { short i; ! 315: char c; ! 316: i=0; ! 317: while (TRUE) ! 318: { c = getkey(); ! 319: if (c==BS) ! 320: { if (i) ! 321: { if (echo) ! 322: { fputc(BS,stderr); ! 323: fputc(' ',stderr); ! 324: fputc(BS,stderr); ! 325: } ! 326: i--; ! 327: } ! 328: continue; ! 329: } ! 330: if (echo) fputc(c,stderr); ! 331: if (c==CR) ! 332: { if (echo) fputc(LF,stderr); ! 333: break; ! 334: } ! 335: if (c==LF) ! 336: break; ! 337: if (c=='\n') ! 338: break; ! 339: if (c<' ') /* any ASCII control character */ ! 340: break; ! 341: strbuf[i++] = c; ! 342: if (i>=maxlen) ! 343: { fprintf(stderr,"\007*\n"); /* -Enough! */ ! 344: while (keypress()) ! 345: getkey(); /* clean up any typeahead */ ! 346: break; ! 347: } ! 348: } ! 349: strbuf[i] = '\0'; /* null termination of string */ ! 350: return(i); /* returns string length */ ! 351: } /* getstring */ ! 352: ! 353: ! 354: void randaccum(short bitcount) /* Get this many random bits ready */ ! 355: /* We will need a series of truly random bits for key generation. ! 356: In most implementations, our random number supply is derived from ! 357: random keyboard delays rather than a hardware random number ! 358: chip. So we will have to ensure we have a large enough pool of ! 359: accumulated random numbers from the keyboard. Later, randombyte ! 360: will return bytes one at a time from the accumulated pool of ! 361: random numbers. For ergonomic reasons, we may want to prefill ! 362: this random pool all at once initially. This routine prefills ! 363: a pool of random bits. */ ! 364: { short nbytes; ! 365: char c; ! 366: nbytes = min((bitcount+7)/8,sizeof(randpool)); ! 367: ! 368: if (randcount < nbytes) /* if we don't have enough already */ ! 369: { fprintf(stderr,"\nWe need to generate %d random bytes. This is done by measuring the", ! 370: nbytes-randcount); ! 371: fprintf(stderr,"\ntime intervals between your keystrokes. Please enter some text on your"); ! 372: fprintf(stderr,"\nkeyboard, at least %d nonrepeating keystrokes, until you hear the bell:\n", ! 373: (8*(nbytes-randcount)+cbits-1)/cbits); ! 374: while (randcount < nbytes) ! 375: { c=getkey(); ! 376: fputc(c,stderr); ! 377: if (c==CR) fputc(LF,stderr); ! 378: } ! 379: fprintf(stderr,"\007*\n-Enough, thank you.\n"); ! 380: while (keypress()) getkey(); /* clean up any typeahead */ ! 381: } /* if (randcount < nbytes) */ ! 382: } /* randaccum */ ! 383:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.