|
|
1.1.1.3 ! 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: ! 5: Revised Jul 88 by PRZ and again Dec 88 by Allan Hoeltje ! 6: to use IBM PC 8253 timer0 for a faster counter. ! 7: Revised Apr 89 by PRZ to recycle random bytes. ! 8: Revised 29 Jul 91 by PRZ for use in more limited environments. ! 9: Later revised by several other folks to run in difficult environments ! 10: such as Unix, VAX/VMS and others. ! 11: Revised 2 Sep 92 by Peter Gutmann and PRZ to use MD5 to distill ! 12: high quality randomness down from low-grade random noise. ! 13: ! 14: This code generates truly random numbers derived from a counter that is ! 15: incremented continuously while the keyboard is scanned for user input. ! 16: Every time the user touches a key, the least significant bits of the ! 17: counter are pushed on a stack. Later, this supply of random bytes can ! 18: be popped off the stack by applications requiring stochastic numbers. ! 19: Cryptographic applications require this kind of randomness. ! 20: ! 21: The only requirement to make this work is that keypress must be called ! 22: frequently, and/or getkey must be called to read the keyboard. ! 23: ! 24: Note that you can only get as many random bytes as the number of ! 25: bytes accumulated by the user touching the keyboard. ! 26: **********************************************************************/ ! 27: ! 28: #include <string.h> ! 29: #include <time.h> ! 30: #include "random.h" ! 31: #include "language.h" ! 32: #ifdef M_XENIX ! 33: long time(); ! 34: #endif ! 35: #ifdef UNIX ! 36: #define clock Clock ! 37: #endif ! 38: ! 39: /* pseudorand() is used mainly for debugging while porting to a new ! 40: machine-- it makes reproducible sequences, which makes debugging ! 41: easier. To use it as the source of random numbers, define ! 42: PSEUDORANDOM. Warning: Don't do this for actual applications. ! 43: */ ! 44: static int randseed=0; /* used only by pseudorand() function. */ ! 45: int pseudorand(void) ! 46: /* Home-grown 16-bit LCG pseudorandom generator. */ ! 47: { randseed = (randseed*31421 + 6927) & 0xffff; ! 48: return (randseed); ! 49: } /* pseudorand */ ! 50: ! 51: ! 52: #ifndef PSEUDORANDOM /* use truly random numbers */ ! 53: ! 54: /* #define USEPCTIMER */ /* use fast hardware timer on IBM PC or AT or clone */ ! 55: /* #define DEBUG */ ! 56: ! 57: /* If operating system shields keyboard event timings from user, then ! 58: we can't use any hardware or software timer logic to time events. ! 59: This is a messy situation, so we have special logic to handle ! 60: it, defining the symbol CRUDE to compile special code. ! 61: This may be needed in some multiuser Unix systems, for example. ! 62: */ ! 63: #ifdef CRUDE /* No environmental support to capture keyboard event times */ ! 64: #undef USEPCTIMER ! 65: #endif /* CRUDE */ ! 66: ! 67: #include <stdio.h> /* for putchar() and printf() */ ! 68: ! 69: /* Prototypes for kbhit() (whether the keyboard has been hit) and getch() ! 70: (like getchar() but no echo, no buffering). Not available under some ! 71: implementations */ ! 72: ! 73: int kbhit( void ); ! 74: int getch( void ); ! 75: ! 76: #ifdef DEBUG ! 77: #define DEBUGprintf1(x) fprintf(stderr,x) ! 78: #define DEBUGprintf2(x,y) fprintf(stderr,x,y) ! 79: #else ! 80: #define DEBUGprintf1(x) ! 81: #define DEBUGprintf2(x,y) ! 82: #endif ! 83: ! 84: ! 85: int randcount = 0 ; /* # of random bytes accumulated in pool */ ! 86: static byte randpool[256] = {0} ; /* pool of truly random bytes */ ! 87: static int recyclecount = 0 ; /* # of recycled random bytes accumulated */ ! 88: static byte recyclepool[256] = {0} ; /* pool of recycled random bytes */ ! 89: static int recycleptr = 0; /* points to next byte to grab in recyclepool */ ! 90: ! 91: /* fastcounter is a free-running counter incremented in main event loop. */ ! 92: static unsigned fastcounter = 0; /* not needed if we can use the PC timer. */ ! 93: static unsigned lastcounter = 0; ! 94: static char toofast = 0; ! 95: /* toofast indicates keystroke rejected because it was typed too fast */ ! 96: ! 97: #ifdef CRUDE ! 98: static boolean capturemode = FALSE; ! 99: #endif /* CRUDE */ ! 100: ! 101: #ifdef AMIGA ! 102: int aecho; ! 103: #endif ! 104: ! 105: /* Information needed by the MD5 code for distilling large quantities of ! 106: semi-random information into a small amount of highly-random information. ! 107: This works as follows: ! 108: ! 109: Initially we have no random information. Whenever we add more slightly ! 110: random data, we put it in the MD5 data field and run MD5 over the ! 111: random byte pool. This propagates the randomness in the data evenly ! 112: throughout the pool due to the avalanche effect of the MD5 transformation. ! 113: The randomness transformation is carried out inside capturecounter() when ! 114: the data is entered, and is transparent to the operation of the rest of ! 115: the code. ! 116: ! 117: The use of this randomness-distillation can be turned off by toggling the ! 118: following define in case the randomness code needs to be run on a ! 119: washing-machine controller or somesuch. ! 120: */ ! 121: ! 122: #define USE_MD5 /* Turn on MD5 randomization */ ! 123: ! 124: #ifdef USE_MD5 ! 125: void Transform( unsigned long *seedBuffer, unsigned long *data ); ! 126: byte seedBuffer[ 64 ]; /* Buffer for MD5 seed value */ ! 127: boolean isInitialised = FALSE; /* Whether buffer has been inited */ ! 128: byte iv[ 16 ]; /* IV for MD5 transformation */ ! 129: #endif /* USE_MD5 */ ! 130: ! 131: #ifdef USEPCTIMER /* we will use fast hardware timer on IBM PC */ ! 132: /* #include <conio.h> */ /* function definitions for inp() and outp() */ ! 133: /* outp() and inp() works only for Microsoft C for IBM PC or AT */ ! 134: /* timer0 on 8253-5 on IBM PC or AT tics every .84 usec. */ ! 135: #define timer0 0x40 /* 8253 timer 0 port */ ! 136: #define timercntl 0x43 /* 8253 control register */ ! 137: #define timer0rwl 0x00 /* read lo/hi bytes of cntr 2 with latch */ ! 138: #define timer0rnl 0x30 /* read lo/hi bytes of cntr 2 w/o latch */ ! 139: ! 140: static byte latched_hitimer = 0; /* captured by keyboard ISR */ ! 141: static byte latched_lotimer = 0; /* captured by keyboard ISR */ ! 142: /* when kbisr captures timer, timer_latched is set. */ ! 143: static boolean timer_latched = FALSE; ! 144: ! 145: static void kbisr(void) /* Keyboard Interrupt Service Routine (ISR) */ ! 146: /* ! 147: kbisr should be called on the way into, or on the way out of, ! 148: or from within the DOS keyboard ISR, as long as it gets called ! 149: at the time of a keyboard interrupt. Assumes that the real ! 150: DOS keyboard ISR captures the keystroke in the normal way. ! 151: Only the hardware timer counter is captured by the kbisr routine, ! 152: leaving the actual keystroke capture to the normal DOS keyboard ISR. ! 153: We indicate that a timer capture has taken place by setting ! 154: timer_latched. ! 155: ! 156: NOTE: WE STILL NEED TO FIND A WAY to connect this subroutine with the ! 157: normal keyboard ISR, so that kbisr gets called when there's a keyboard ! 158: interrupt. ! 159: */ ! 160: { outp(timercntl,timer0rwl); ! 161: latched_lotimer = inp(timer0); ! 162: latched_hitimer = inp(timer0); ! 163: timer_latched = TRUE; ! 164: } /* kbisr */ ! 165: ! 166: static unsigned short pctimer0(void) ! 167: { ! 168: /* Reads and returns the hardware 8253 timer0 on the PC or AT ! 169: ** or clone, shifted right 1 bit. ! 170: ** ! 171: ** DO NOT SET THE HARDWARE COUNTER TO ZERO. It is already initialized ! 172: ** by the system to be used by the clock. It is set up in mode 3 ! 173: ** (square wave rate generator) and counts down by 2 from 0 (0xFFFF+1) ! 174: ** to produce an 18.2 Hz square wave. We may, however, READ the ! 175: ** lo and hi bytes without causing any problems. BUT just ! 176: ** remember that the lo byte will always be even (since it is ! 177: ** counting by two). ! 178: ** ! 179: ** Note that we can not use counter 1 since it is tied to the ! 180: ** dynamic RAM refresh hardware. Counter 2 is tied to the 8255 ! 181: ** PPI chip to do things like sound. Though it would be safe to ! 182: ** use counter 2 it is not desirable since we would have to turn ! 183: ** the speaker on in order to make the timer count! Normally one ! 184: ** sets counter 2 to mode 3 (square wave generator) to sound the ! 185: ** speaker. You can set mode 2 (pulse generator) and the speaker ! 186: ** hardly makes any sound at all, a click when you turn it on and ! 187: ** a click when you turn it off. Counter 0 should be safe if ! 188: ** we only read the counter bytes. ! 189: ** ! 190: ** WARNING: To use the hardware timer the way it really should be ! 191: ** used, we ought to capture it via a keyboard interrupt service ! 192: ** routine (ISR). Otherwise, we may experience weaknesses in randomness ! 193: ** due to harmonic relationships between the hardware counter frequency ! 194: ** and the keyboard software polling frequency. Unfortunately, this ! 195: ** implementation does not currently use keyboard interrupts to ! 196: ** capture the counter. This is not a problem if we don't use the ! 197: ** hardware counter, but instead use the software counter fastcounter. ! 198: ** Thus, the hardware counter should not be used at all, unless we ! 199: ** support it with an ISR. ! 200: */ ! 201: unsigned short t ; ! 202: /* See if timer has been latched by kbisr(). */ ! 203: if (!timer_latched) /* The timer was not already latched. */ ! 204: kbisr(); /* latch timer */ ! 205: /* return latched timer and clear latch */ ! 206: t = ( (((unsigned short) latched_hitimer) << 8) | ! 207: ((unsigned short) latched_lotimer) ! 208: ) >> 1 ; ! 209: timer_latched = FALSE; ! 210: return (t) ; ! 211: } /* pctimer0 */ ! 212: ! 213: #endif /* ifdef USEPCTIMER */ ! 214: ! 215: ! 216: /* keybuf is used only by keypress(), getkey(), and capturecounter(). */ ! 217: static short keybuf = 0; ! 218: ! 219: ! 220: #ifdef VMS ! 221: ! 222: extern unsigned long vms_clock_bits[2]; /* VMS Hardware Clock */ ! 223: extern const long vms_ticks_per_update; /* Clock update int. */ ! 224: ! 225: #endif /* VMS */ ! 226: ! 227: void capturecounter(void) ! 228: /* Push a fast counter on the random stack. Should be called when ! 229: ** the user touches a key or clicks the mouse. ! 230: */ ! 231: { ! 232: int dt, i, j; ! 233: #ifndef USE_MD5 ! 234: static unsigned int accum = 0; ! 235: #endif /* USE_MD5 */ ! 236: static byte abits = 0; /* number of accumulated bits in accum */ ! 237: unsigned int accum1; ! 238: ! 239: #define cbitsmask ((1 << cbits)-1) ! 240: ! 241: #ifdef CRUDE /* No environmental support to capture keyboard event times. */ ! 242: if (!capturemode) ! 243: return; /* only captures during randaccum function */ ! 244: #endif /* CRUDE */ ! 245: ! 246: /* fastcounter only contains timing information, in the form of a ! 247: free-running timer, either hardware or software. ! 248: accum1 contains stuff from fastcounter and other sources, ! 249: like the actual key the user hit. ! 250: */ ! 251: ! 252: #if defined(USEPCTIMER) /* we will use fast hardware timer on IBM PC */ ! 253: #define cbits 8 /* number of bits of counter to capture each time */ ! 254: fastcounter = pctimer0(); /* capture hardware timer */ ! 255: #else ! 256: #if defined(CRUDE) /* no fast hardware timer available */ ! 257: #define cbits 2 ! 258: #else /* not CRUDE */ ! 259: #ifndef cbits ! 260: #define cbits 4 /* number of bits of counter to capture each time */ ! 261: #endif ! 262: #ifdef VMS ! 263: #define cbits 2 /* fewer bits because VMS timer is so slow (100 Hz) */ ! 264: /* Capture fast system timer: */ ! 265: SYS$GETTIM(vms_clock_bits); ! 266: #ifdef TEST_COUNTER ! 267: fprintf(stderr," time %10ol %10ol\n",vms_clock_bits[0],vms_clock_bits[1]); ! 268: #endif ! 269: /* vms_clock_bits[0] and vms_ticks_per_update are 32-bits each. */ ! 270: fastcounter = vms_clock_bits[0] / vms_ticks_per_update; ! 271: #endif /* VMS */ ! 272: #endif /* not CRUDE */ ! 273: #endif /* not USEPCTIMER */ ! 274: ! 275: #ifndef CRUDE /* keyboard timings are available */ ! 276: dt = fastcounter - lastcounter; ! 277: if (dt < 0) /* timer rolled over past zero */ ! 278: dt = -dt; /* absolute value of time elapsed */ ! 279: #ifdef TEST_COUNTER ! 280: fprintf(stderr,"<dt=%6u>\n", dt); ! 281: #endif ! 282: if ( ((unsigned) dt) < (unsigned)(1 << (cbits + 2))) ! 283: { ! 284: toofast++; /* indicate a too-fast keystroke */ ! 285: return; /* only captures if enough time has passed */ ! 286: } ! 287: #endif /* not CRUDE */ ! 288: ! 289: lastcounter = fastcounter; /* latch timer info */ ! 290: ! 291: #ifdef USE_MD5 ! 292: /* Initialise the MD5 info if necessary */ ! 293: if( !isInitialised ) /* we probably shouldn't bother */ ! 294: { memset(seedBuffer, 0, 64); ! 295: memset(iv, 0, 16); ! 296: isInitialised = TRUE; ! 297: } ! 298: ! 299: /* Add the slightly-random data to the MD5 input buffer. Currently we ! 300: just add a few bytes of environmental noise, but we could mix in ! 301: up to 512 bits worth. ! 302: */ ! 303: seedBuffer[ 0 ] = keybuf; /* actual character user typed */ ! 304: seedBuffer[ 1 ] = lastcounter & 0xFF; ! 305: seedBuffer[ 2 ] = lastcounter >> 8; ! 306: accum1 = ( int ) clock(); /* clock ticks */ ! 307: seedBuffer[ 3 ] = accum1 & 0xFF; ! 308: seedBuffer[ 4 ] = accum1 >> 8; ! 309: accum1 = ( int ) time(NULL); /* seconds */ ! 310: seedBuffer[ 5 ] = accum1 & 0xFF; ! 311: seedBuffer[ 6 ] = accum1 >> 8; ! 312: /* The preceding "noise quantum" has only cbits worth of randomness. */ ! 313: ! 314: /* Now use MD5 to diffuse the randomness in these bits over the random ! 315: byte pool, raising the salinity of randomness in the pool. The ! 316: transformation is carried out by "encrypting" the data in CFB mode ! 317: with MD5 as the block cipher */ ! 318: for(i = 0; i < sizeof(randpool); i += 16) ! 319: { ! 320: Transform((unsigned long *) iv, (unsigned long *) seedBuffer); ! 321: for(j = 0; j < 16; j++) ! 322: randpool[i+j] ^= iv[j]; ! 323: memcpy(iv, randpool+i, 16); ! 324: } ! 325: ! 326: /* ! 327: Now the somewhat dubious bit: In order to make this fit in with ! 328: the existing code, we use the existing mechanism of keeping track ! 329: of a high-water mark in the buffer. This is actually reasonably ! 330: realistic, since it keeps a count of what percentage of the full ! 331: buffer is random enough-- measuring the "molarity" of solution. ! 332: However when it comes time to re-randomize the buffer in ! 333: randombyte(), it would probably be better to use the above ! 334: transformation than the existing randombyte() code. I've left it ! 335: as is to keep it as compatible as possible. ! 336: */ ! 337: ! 338: abits += cbits; /* Update count of bits of randomness */ ! 339: while (abits >= 8) ! 340: { /* We've got another byte's worth, increment the buffer pointer */ ! 341: if (randcount < sizeof(randpool)) ! 342: randcount++; /* not a byte counter-- now a molarity of randomness */ ! 343: abits -= 8; ! 344: } ! 345: #else /* not USE_MD5 */ ! 346: /* combine several sources to attempt maximum randomness... */ ! 347: accum1 = keybuf; /* actual keystroke */ ! 348: accum1 += lastcounter; /* add latched timer info */ ! 349: accum1 += clock(); /* clock ticks */ ! 350: accum1 += time(NULL); /* seconds */ ! 351: ! 352: accum1 ^= (accum1 >> cbits); /* Fold upper and lower bits */ ! 353: ! 354: /* slide some new bits into the bit accumulator: */ ! 355: accum = (accum << cbits) | (unsigned int) (accum1 & cbitsmask); ! 356: abits += cbits; ! 357: while (abits >= 8) /* another byte's worth of bits accumulated */ ! 358: { if (randcount < sizeof(randpool)) ! 359: /* take lower byte of accum */ ! 360: randpool[randcount++] = accum; ! 361: abits -= 8; ! 362: accum >>= 8; ! 363: } ! 364: #endif /* not USE_MD5 */ ! 365: #undef cbitsmask ! 366: } /* capturecounter */ ! 367: ! 368: ! 369: /* Because these truly random bytes are so unwieldy to accumulate, ! 370: they can be regarded as a precious resource. Unfortunately, ! 371: cryptographic key generation algorithms may require a great many ! 372: random bytes while searching about for large random prime numbers. ! 373: Fortunately, they need not all be truly random. We only need as ! 374: many truly random bytes as there are bytes in the large prime we ! 375: are searching for. These random bytes can be recycled and modified ! 376: via pseudorandom numbers until the key is generated, without losing ! 377: any of the integrity of randomness of the final key. ! 378: */ ! 379: ! 380: ! 381: static void randstir(void) ! 382: /* Stir up the recycled random number bin, via a pseudorandom generator */ ! 383: { int i; ! 384: i = recyclecount; ! 385: while (i--) ! 386: recyclepool[i] ^= (byte) pseudorand(); ! 387: DEBUGprintf2(" Stirring %d recycled bytes. ",recyclecount); ! 388: } /* randstir */ ! 389: ! 390: ! 391: short randload(short bitcount) ! 392: /* Flushes stale recycled random bits and copies a fresh supply of raw ! 393: random bits from randpool to recyclepool. Returns actual number of ! 394: bits transferred. */ ! 395: { int bytecount; ! 396: bytecount = (bitcount+7)/8; ! 397: bytecount = min(bytecount,randcount); ! 398: randflush(); /* reset recyclecount, discarding recyclepool */ ! 399: while (bytecount--) ! 400: recyclepool[recyclecount++] = randpool[--randcount]; ! 401: DEBUGprintf2("\nAllocating %d recycleable random bytes. ",recyclecount); ! 402: return(recyclecount*8); ! 403: } /* randload */ ! 404: ! 405: ! 406: void randflush(void) /* destroys pool of recycled random numbers */ ! 407: /* Ensures no sensitive data remains in memory that can be recovered later. */ ! 408: { recyclecount = sizeof (recyclepool); ! 409: while (recyclecount) ! 410: recyclepool[--recyclecount]=0; ! 411: /* recyclecount is left at 0 */ ! 412: recycleptr = 0; ! 413: memset(seedBuffer, 0, 64); ! 414: memset(iv, 0, 16); ! 415: } /* randflush */ ! 416: ! 417: ! 418: short randombyte(void) ! 419: /* Returns truly random byte from pool, or a pseudorandom value ! 420: ** if pool is empty. It is recommended that the caller check ! 421: ** the value of randcount before calling randombyte. ! 422: */ ! 423: { ! 424: /* First try to get a cheap recycled random byte, if there are any. */ ! 425: if (recyclecount) /* nonempty recycled pool */ ! 426: { if (++recycleptr >= recyclecount) /* ran out? */ ! 427: { recycleptr = 0; /* ran out of recycled random numbers */ ! 428: randstir(); /* stir up recycled bits */ ! 429: } ! 430: return (recyclepool[recycleptr]); ! 431: } ! 432: ! 433: /* Empty recycled pool. Try a more expensive fresh random byte. */ ! 434: if (randcount) /* nonempty random pool--return a very random number */ ! 435: return (randpool[--randcount]); ! 436: ! 437: /* Alas, fresh random pool is empty. Get a pseudorandom byte. ! 438: Pseudorandom numbers are bad for cryptographic applications. ! 439: Although we will return a pseudorandom byte in the low order byte, ! 440: indicate error by making the result negative in the high byte. ! 441: */ ! 442: /* DEBUGprintf1("\007Warning: random pool empty! "); */ ! 443: return ( (pseudorand() & 0xFF) ^ (-1) ); ! 444: } /* randombyte */ ! 445: ! 446: ! 447: boolean keypress(void) /* TRUE iff keyboard input ready */ ! 448: { /* Accumulates random numbers by timing user keystrokes. */ ! 449: #ifndef CRUDE ! 450: static short lastkey = 0; /* used to detect autorepeat key sequences */ ! 451: static short next_to_lastkey = 0; /* allows a single repeated key */ ! 452: ! 453: #ifndef USEPCTIMER /* no fast hardware timer available */ ! 454: fastcounter++; /* used in lieu of fast hardware timer counter */ ! 455: #endif /* ifndef USEPCTIMER */ ! 456: ! 457: if (keybuf & 0x100) /* bit 8 means keybuf contains valid data */ ! 458: return( TRUE ); /* key was hit the last time thru */ ! 459: ! 460: if (kbhit() == 0) /* keyboard was not hit */ ! 461: return( FALSE ); ! 462: ! 463: keybuf = getch() | 0x100; /* set data latch bit */ ! 464: ! 465: /* Keyboard was hit. Decide whether to call capturecounter... */ ! 466: ! 467: /* Guard against typahead buffer defeating fastcounter's randomness. ! 468: ** This could be a problem for multicharacter sequences generated ! 469: ** by a function key expansion or by the user generating keystrokes ! 470: ** faster than our event loop can handle them. Only the last ! 471: ** character of a multicharacter sequence will trigger the counter ! 472: ** capture. Also, don't let the keyboard's autorepeat feature ! 473: ** produce nonrandom counter capture. However, we do allow a ! 474: ** single repeated character to trigger counter capture, because ! 475: ** many english words have double letter combinations, and it's ! 476: ** unlikely a typist would exploit the autorepeat feature to ! 477: ** type a simple double letter sequence. ! 478: ** We have some separate checks in capturecounter() to guard ! 479: ** against other reasons for characters coming in too fast. ! 480: */ ! 481: ! 482: if (kbhit() == 0) /* nothing in typahead buffer */ ! 483: { /* don't capture counter if key repeated */ ! 484: if (keybuf != lastkey) ! 485: capturecounter(); /* read random noise from environment */ ! 486: else if (keybuf != next_to_lastkey) /* allow single repeat */ ! 487: capturecounter(); ! 488: next_to_lastkey = lastkey; ! 489: lastkey = keybuf; ! 490: } ! 491: return( TRUE ); ! 492: #else /* CRUDE */ ! 493: return(FALSE); ! 494: #endif ! 495: } /* keypress */ ! 496: ! 497: ! 498: short getkey(void) /* Returns data from keyboard (no echo). */ ! 499: { /* Also accumulates random numbers via keypress(). */ ! 500: #ifndef CRUDE ! 501: while(! keypress() ); /* loop until key is pressed. */ ! 502: return( keybuf &= 0xff); /* clear latch bit 8 */ ! 503: #else ! 504: return(keybuf = getch() & 0xff); ! 505: #endif ! 506: } /* getkey */ ! 507: ! 508: ! 509: #define BS 8 /* ASCII backspace */ ! 510: #define CR 13 /* ASCII carriage return */ ! 511: #define LF 10 /* ASCII linefeed */ ! 512: #define DEL 0177 /* ASCII delete */ ! 513: ! 514: /* We will need a series of truly random bits for key generation. ! 515: In most implementations, our random number supply is derived from ! 516: random keyboard delays rather than a hardware random number ! 517: chip. So we will have to ensure we have a large enough pool of ! 518: accumulated random numbers from the keyboard. Later, randombyte ! 519: will return bytes one at a time from the accumulated pool of ! 520: random numbers. For ergonomic reasons, we may want to prefill ! 521: this random pool all at once initially. The randaccum function ! 522: prefills a pool of random bits. ! 523: */ ! 524: ! 525: #if defined(UNIX) || defined(AMIGA) || defined(VMS) ! 526: #define NEEDBREAK ! 527: void ttycbreak(); ! 528: void ttynorm(); ! 529: #endif ! 530: ! 531: #ifndef CRUDE /* We can measure keyboard event times accurately. */ ! 532: ! 533: void randaccum(short bitcount) /* Get this many random bits ready */ ! 534: { short nbytes; ! 535: char c; ! 536: int col = 0; ! 537: unsigned long timer; ! 538: int fasts_rejected = 0; /* number of too-fast keystrokes */ ! 539: ! 540: nbytes = min((bitcount+7)/8,sizeof(randpool)); ! 541: fasts_rejected = 0; /* number of too-fast keystrokes */ ! 542: toofast = 0; /* clear too-fast latch */ ! 543: ! 544: if (randcount < nbytes) /* if we don't have enough already */ ! 545: { fprintf(stderr, ! 546: PSTR("\nWe need to generate %d random bytes. This is done by measuring the\ ! 547: \ntime intervals between your keystrokes. Please enter some text on your\ ! 548: \nkeyboard, at least %d nonrepeating keystrokes, until you hear the beep:\n"), ! 549: nbytes-randcount, (8*(nbytes-randcount)+cbits-1)/cbits); ! 550: #ifdef NEEDBREAK ! 551: ttycbreak(); ! 552: #endif ! 553: /* display counter to show progress */ ! 554: ! 555: while (randcount < nbytes) ! 556: { ! 557: fprintf(stderr,"\r%3d ",nbytes-randcount); ! 558: fflush(stderr); ! 559: c=getkey(); ! 560: if (toofast) ! 561: { fasts_rejected++; /* keep score */ ! 562: toofast = 0; /* reset latch */ ! 563: putc('?', stderr); /* indicate trouble */ ! 564: } ! 565: else ! 566: putc('.', stderr); ! 567: } ! 568: ! 569: fprintf(stderr,PSTR("\007*\n-Enough, thank you.\n")); ! 570: ! 571: if (fasts_rejected > 2) /* Did user type too fast? */ ! 572: fprintf(stderr,PSTR("(Ignored %d keystrokes that were typed too fast.)\n"), ! 573: fasts_rejected); ! 574: ! 575: /* Clean up typeahead for at least 1 full second... */ ! 576: timer = time(NULL) + 1; /* need at least 1 second of quiet */ ! 577: while ((unsigned long) time(NULL) <= timer) ! 578: { if (keypress()) /* user touched a key, reset timer */ ! 579: { getkey(); ! 580: timer = time(NULL) + 1; ! 581: } ! 582: } ! 583: ! 584: #ifdef NEEDBREAK ! 585: ttynorm(); ! 586: #endif /* !NEEDBREAK */ ! 587: } ! 588: } /* randaccum */ ! 589: ! 590: #endif /* not CRUDE */ ! 591: ! 592: ! 593: #ifdef CRUDE /* We cannot measure keyboard event times accurately. */ ! 594: ! 595: /* If we can't measure keyboard event timings, use the actual keys ! 596: typed as the source of randomness. ! 597: ! 598: This is a really lousy way to make random numbers. We will only use ! 599: this method as a last resort, only if this machine does not allow ! 600: keyboard events to be timed accurately. It's better than nothing. ! 601: The other randaccum function listed above is much better, if the ! 602: CRUDE symbol is undefined and the environment will support it. ! 603: ! 604: We have improved this scheme somewhat by using a good hashing ! 605: function (MD5) on the user input before capturing it in the ! 606: random pool. This is done in function capturecounter(). ! 607: */ ! 608: ! 609: void randaccum(short bitcount) /* Get this many random bits ready */ ! 610: { short nbytes; ! 611: char c, flushbuf[80]; ! 612: nbytes = min((bitcount+7)/8,sizeof(randpool)); ! 613: ! 614: randcount = 0; /* start with nothing in pool. */ ! 615: capturemode = TRUE; /* enable capture of random keys */ ! 616: fastcounter += time(0); /* start with time of day, if available */ ! 617: ! 618: fprintf(stderr,PSTR("\nWe need to generate %d random bytes.\ ! 619: \nPlease enter at least %d random keystrokes, as random\ ! 620: \nas you can possibly make them.\n"), ! 621: nbytes-randcount, (8*(nbytes-randcount)+cbits-1)/cbits); ! 622: while (randcount < nbytes) ! 623: { c=getkey(); ! 624: capturecounter(); ! 625: } ! 626: /* ! 627: * CRUDE mode must work in normal tty mode, so we can't ! 628: * use keypress() to flush input. ! 629: */ ! 630: #ifdef AMIGA ! 631: while(keypress()) getch(); ! 632: #else ! 633: fgets(flushbuf, sizeof(flushbuf), stdin); ! 634: #endif ! 635: fprintf(stderr,PSTR("\007 -Enough, thank you.\n")); ! 636: ! 637: capturemode = FALSE; /* don't capture any more keys */ ! 638: ! 639: #ifdef NEEDBREAK ! 640: ttynorm(); ! 641: #endif ! 642: } /* randaccum */ ! 643: ! 644: #endif /* CRUDE */ ! 645: ! 646: ! 647: int getstring(char *strbuf, int maxlen, boolean echo) ! 648: /* Gets string from user, with no control characters allowed. ! 649: Also accumulates random numbers by calling getkey(). ! 650: maxlen is max length allowed for string. ! 651: echo is TRUE iff we should echo keyboard to screen. ! 652: Returns null-terminated string in strbuf. ! 653: */ ! 654: { short i; ! 655: char c; ! 656: #ifdef NEEDBREAK ! 657: ttycbreak(); ! 658: #endif ! 659: #ifdef AMIGA ! 660: aecho = (int)echo; ! 661: echo = FALSE; /* echo is done in getch */ ! 662: #endif /* AMIGA */ ! 663: fflush(stdout); ! 664: i=0; ! 665: while (TRUE) ! 666: { fflush(stderr); ! 667: c = getkey(); ! 668: if (c==BS || c==DEL) ! 669: { if (i) ! 670: { if (echo) ! 671: { fputc(BS,stderr); ! 672: fputc(' ',stderr); ! 673: fputc(BS,stderr); ! 674: } ! 675: i--; ! 676: } ! 677: continue; ! 678: } ! 679: if (c < ' ' && c != LF && c != CR) ! 680: { putc('\007', stderr); ! 681: continue; ! 682: } ! 683: if (echo) fputc(c,stderr); ! 684: if (c==CR) ! 685: { if (echo) fputc(LF,stderr); ! 686: break; ! 687: } ! 688: if (c==LF) ! 689: break; ! 690: if (c=='\n') ! 691: break; ! 692: strbuf[i++] = c; ! 693: if (i>=maxlen) ! 694: { fprintf(stderr,"\007*\n"); /* -Enough! */ ! 695: while (keypress()) ! 696: getkey(); /* clean up any typeahead */ ! 697: break; ! 698: } ! 699: } ! 700: strbuf[i] = '\0'; /* null termination of string */ ! 701: #ifdef NEEDBREAK ! 702: ttynorm(); ! 703: #endif ! 704: return(i); /* returns string length */ ! 705: } /* getstring */ ! 706: ! 707: ! 708: #endif /* ifndef PSEUDORANDOM */ ! 709: ! 710: void flush_input() ! 711: { ! 712: #ifdef NEEDBREAK ! 713: ttycbreak(); ! 714: #endif ! 715: while (keypress()) /* flush typahead buffer */ ! 716: getkey(); ! 717: #ifdef NEEDBREAK ! 718: ttynorm(); ! 719: #endif ! 720: } ! 721:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.