--- pgp/src/random.c 2018/04/24 16:37:52 1.1 +++ pgp/src/random.c 2018/04/24 16:40:51 1.1.1.6 @@ -1,383 +1,479 @@ -/********************************************************************** - random.c - C source code for random number generation - 19 Nov 86 - (c) Copyright 1986 by Philip Zimmermann. All rights reserved. - Revised Jul 88 by PRZ and again Dec 88 by Allan Hoeltje - to use IBM PC 8253 timer0 for a faster counter. - Revised Apr 89 by PRZ to recycle random bytes. - Last revised 15 Dec 90 by PRZ. - - This code generates truly random numbers derived from a counter that is - incremented continuously while the keyboard is scanned for user input. - Every time the user touches a key, the least significant bits of the - counter are pushed on a stack. Later, this supply of random bytes can - be popped off the stack by applications requiring stochastic numbers. - Cryptographic applications require this kind of randomness. - - The only requirement to make this work is that keypress must be called - frequently, and/or getkey must be called to read the keyboard. - - Note that you can only get as many random bytes as the number of - bytes accumulated by the user touching the keyboard. -**********************************************************************/ - -#include /* for putchar() and printf() */ -#include /* for kbhit() and getch() */ -#include "random.h" - -/* #define USEPCTIMER /* use fast hardware timer on IBM PC or AT or clone */ -/* #define DEBUG */ - -#ifdef DEBUG -#define DEBUGprintf1(x) fprintf(stderr,x) -#define DEBUGprintf2(x,y) fprintf(stderr,x,y) -#else -#define DEBUGprintf1(x) -#define DEBUGprintf2(x,y) -#endif +/* + * True and cryptographic random number generation. + * + * (c) Copyright 1990-1994 by Philip Zimmermann. All rights reserved. + * The author assumes no liability for damages resulting from the use + * of this software, even if the damage results from defects in this + * software. No warranty is expressed or implied. + * + * Note that while most PGP source modules bear Philip Zimmermann's + * copyright notice, many of them have been revised or entirely written + * by contributors who frequently failed to put their names in their + * code. Code that has been incorporated into PGP from other authors + * was either originally published in the public domain or is used with + * permission from the various authors. + * + * PGP is available for free to the public under certain restrictions. + * See the PGP User's Guide (included in the release package) for + * important information about licensing, patent restrictions on + * certain algorithms, trademarks, copyrights, and export controls. + * + * Written by Colin Plumb. + */ + +#include +#include +#include +#include +#include /* For SIGINT */ +#include + +#include "system.h" /* For ttycbreak, getch, etc. */ +#include "idea.h" +#include "md5.h" +#include "noise.h" +#include "language.h" +#include "random.h" +#include "fileio.h" /* For FOPRBIN */ +#include "pgp.h" /* For globalRandseedName */ +#include "randpool.h" + +static struct IdeaRandContext randContext; +static int randInitFlag = 0; + +/* + * Load the RNG state from the randseed.bin file on disk. + * Returns 0 on success, <0 on error. + */ +int +cryptRandOpen(void) +{ + byte buf[24]; + int len; + FILE *f; + + if (randInitFlag) + return 0; + + f = fopen(globalRandseedName, FOPRBIN); + if (!f) + return -1; + len = fread((char *)buf, 1, 24, f); + fclose(f); + ideaRandInit(&randContext, buf, buf+16); + randInitFlag = 1; + return (len == 24) ? 0 : -1; +} -static int randseed=0; /* used only by pseudorand() function. */ -int pseudorand(void) -/* Home-grown 16-bit LCG pseudorandom generator. */ -{ randseed = (randseed*31421 + 6927) & 0xffff; - return (randseed); -} /* pseudorand */ - - -int randcount = 0 ; /* # of random bytes accumulated in pool */ -static byte randpool[256] = {0} ; /* pool of truly random bytes */ -static int recyclecount = 0 ; /* # of recycled random bytes accumulated */ -static byte recyclepool[256] = {0} ; /* pool of recycled random bytes */ -static int recycleptr = 0; /* points to next byte to grab in recyclepool */ - -/* fastcounter is a free-running counter incremented in main event loop */ -static byte fastcounter = 0; /* not needed if we can use the PC timer. */ - - -#ifdef USEPCTIMER /* we will use fast hardware timer on IBM PC */ -/* #include /* function definitions for inp() and outp() */ -/* outp() and inp() works only for Microsoft C for IBM PC or AT */ -/* timer0 on 8253-5 on IBM PC or AT tics every .84 usec. */ -#define timer0 0x40 /* 8253 timer 0 port */ -#define timercntl 0x43 /* 8253 control register */ -#define timer0rwl 0x00 /* read lo/hi bytes of cntr 2 with latch */ -#define timer0rnl 0x30 /* read lo/hi bytes of cntr 2 w/o latch */ - -static byte latched_hitimer = 0; /* captured by keyboard ISR */ -static byte latched_lotimer = 0; /* captured by keyboard ISR */ -/* when kbisr captures timer, timer_latched is set. */ -static boolean timer_latched = FALSE; - -static void kbisr(void) /* Keyboard Interrupt Service Routine (ISR) */ -/* - kbisr should be called on the way into, or on the way out of, - or from within the DOS keyboard ISR, as long as it gets called - at the time of a keyboard interrupt. Assumes that the real - DOS keyboard ISR captures the keystroke in the normal way. - Only the hardware timer counter is captured by the kbisr routine, - leaving the actual keystroke capture to the normal DOS keyboard ISR. - We indicate that a timer capture has taken place by setting - timer_latched. - - NOTE: WE STILL NEED TO FIND A WAY to connect this subroutine with the - normal keyboard ISR, so that kbisr gets called when there's a keyboard - interrupt. -*/ -{ outp(timercntl,timer0rwl); - latched_lotimer = inp(timer0); - latched_hitimer = inp(timer0); - timer_latched = TRUE; -} /* kbisr */ - -static unsigned short pctimer0(void) -{ -/* Reads and returns the hardware 8253 timer0 on the PC or AT -** or clone, shifted right 1 bit. -** -** DO NOT SET THE HARDWARE COUNTER TO ZERO. It is already initialized -** by the system to be used by the clock. It is set up in mode 3 -** (square wave rate generator) and counts down by 2 from 0 (0xFFFF+1) -** to produce an 18.2 Hz square wave. We may, however, READ the -** lo and hi bytes without causing any problems. BUT just -** remember that the lo byte will always be even (since it is -** counting by two). -** -** Note that we can not use counter 1 since it is tied to the -** dynamic RAM refresh hardware. Counter 2 is tied to the 8255 -** PPI chip to do things like sound. Though it would be safe to -** use counter 2 it is not desirable since we would have to turn -** the speaker on in order to make the timer count! Normally one -** sets counter 2 to mode 3 (square wave generator) to sound the -** speaker. You can set mode 2 (pulse generator) and the speaker -** hardly makes any sound at all, a click when you turn it on and -** a click when you turn it off. Counter 0 should be safe if -** we only read the counter bytes. -** -** WARNING: To use the hardware timer the way it really should be -** used, we ought to capture it via a keyboard interrupt service -** routine (ISR). Otherwise, we may experience weaknesses in randomness -** due to harmonic relationships between the hardware counter frequency -** and the keyboard software polling frequency. Unfortunately, this -** implementation does not currently use keyboard interrupts to -** capture the counter. This is not a problem if we don't use the -** hardware counter, but instead use the software counter fastcounter. -** Thus, the hardware counter should not be used at all, unless we -** support it with an ISR. -*/ - unsigned short t ; - /* See if timer has been latched by kbisr(). */ - if (!timer_latched) /* The timer was not already latched. */ - kbisr(); /* latch timer */ - /* return latched timer and clear latch */ - t = ( (((unsigned short) latched_hitimer) << 8) | - ((unsigned short) latched_lotimer) - ) >> 1 ; - timer_latched = FALSE; - return (t) ; -} /* pctimer0 */ - -#endif /* ifdef USEPCTIMER */ - - -void capturecounter(void) -/* Push a fast counter on the random stack. Should be called when -** the user touches a key or clicks the mouse. -*/ -{ - static unsigned int accum = 0; - static byte abits = 0; /* number of accumulated bits in accum */ - -#ifdef USEPCTIMER /* we will use fast hardware timer on IBM PC */ -#define cbits 8 /* number of bits of counter to capture each time */ - fastcounter += pctimer0(); -#else /* no fast hardware timer available */ -#define cbits 4 /* number of bits of counter to capture each time */ -#endif /* ifdef USEPCTIMER */ -#define cbitsmask ((1 << cbits)-1) - - accum = (accum << cbits) | (unsigned int) (fastcounter & cbitsmask); - abits += cbits; - while (abits >= 8) - { if (randcount < sizeof(randpool)) - /* take lower byte of accum */ - randpool[randcount++] = accum; - abits -= 8; - accum >>= 8; +void +cryptRandCreate(void) +{ + byte randbuf[24]; + int i; + FILE *f; + + for (i = 0; i < 24; i++) + randbuf[i] = trueRandByte(); + + ideaRandInit(&randContext, (byte *)randbuf, (byte *)randbuf+16); + randInitFlag = 1; + + f = fopen(globalRandseedName, FOPWBIN); + if (f) { + fwrite(randbuf, 1, 24, f); + fclose(f); } - fastcounter = 0; -#undef cbitsmask -} /* capturecounter */ - - -/* Because these truly random bytes are so unwieldy to accumulate, - they can be regarded as a precious resource. Unfortunately, - cryptographic key generation algorithms may require a great many - random bytes while searching about for large random prime numbers. - Fortunately, they need not all be truly random. We only need as - many truly random bytes as there are bytes in the large prime we - are searching for. These random bytes can be recycled and modified - via pseudorandom numbers until the key is generated, without losing - any of the integrity of randomness of the final key. -*/ - - -static void randstir(void) -/* Stir up the recycled random number bin, via a pseudorandom generator */ -{ int i; - i = recyclecount; - while (i--) - recyclepool[i] ^= (byte) pseudorand(); - DEBUGprintf2(" Stirring %d recycled bytes. ",recyclecount); -} /* randstir */ - - -short randload(short bitcount) -/* Flushes stale recycled random bits and copies a fresh supply of raw - random bits from randpool to recyclepool. Returns actual number of - bits transferred. Formerly named randrecycle. */ -{ int bytecount; - bytecount = (bitcount+7)/8; - bytecount = min(bytecount,randcount); - randflush(); /* reset recyclecount, discarding recyclepool */ - while (bytecount--) - recyclepool[recyclecount++] = randpool[--randcount]; - DEBUGprintf2("\nAllocating %d recycleable random bytes. ",recyclecount); - return(recyclecount*8); -} /* randload */ - - -void randflush(void) /* destroys pool of recycled random numbers */ -/* Ensures no sensitive data remains in memory that can be recovered later. */ -{ recyclecount = sizeof (recyclepool); - while (recyclecount) - recyclepool[--recyclecount]=0; - /* recyclecount is left at 0 */ - recycleptr = 0; -} /* randflush */ - - -short randombyte(void) -/* Returns truly random byte from pool, or a pseudorandom value -** if pool is empty. It is recommended that the caller check -** the value of randcount before calling randombyte. -*/ -{ - /* First try to get a cheap recycled random byte, if there are any. */ - if (recyclecount) /* nonempty recycled pool */ - { if (++recycleptr >= recyclecount) /* ran out? */ - { recycleptr = 0; /* ran out of recycled random numbers */ - randstir(); /* stir up recycled bits */ - } - return (recyclepool[recycleptr]); + return; +} + +/* + * Encrypt the state of the PRNG with the given key. It is intended + * that this key is the md5 of the message to be encrypted, which is + * unpredictable to a would-be attacker who does not posess the message. + * This is simply a way to get some "random" bytes without a random + * number source. This "prewash" attempts to reduce the value of a + * captured randseed.bin file. + */ +void +cryptRandWash(byte const key[16]) +{ + struct IdeaCfbContext cfb; + + if (!randInitFlag) + cryptRandOpen(); + ideaCfbInit(&cfb, key); + ideaRandWash(&randContext, &cfb); + ideaCfbDestroy(&cfb); +} + +byte +cryptRandByte(void) +{ + if (!randInitFlag) + cryptRandOpen(); + return ideaRandByte(&randContext); +} + +/* + * Create a new RNG state, encrypt it with the session key, and save it + * out to disk. The RNG is re-initialized with the saved parameters. + * + * This uses the same key and initial vector (including the repeated + * check bytes and everything) that is used to encrypt the user's message. + * The hope is that this "postwash" renders it is at least as hard to + * derive old session keys from randseed.bin as it is to crack the the + * message directly. + * + * The purpose of using EXACTLY the same encryption is to make sure that + * there isn't related, but different data floating around that can be + * used for cryptanalysis. + */ +void +cryptRandSave(byte const key[16], byte const iv[8]) +{ + struct IdeaCfbContext cfb; + byte buf[24]; + FILE *f; + int i; + + /* This IV is EXACTLY the same as is used on bulk files. */ + memcpy(buf, iv, 8); + buf[8] = buf[6]; /* "check bytes" */ + buf[9] = buf[7]; + + ideaCfbInit(&cfb, key); + ideaCfbEncrypt(&cfb, buf, buf, 10); + ideaCfbSync(&cfb); + for (i = 0; i < 24; i++) + buf[i] = ideaRandByte(&randContext); + ideaCfbEncrypt(&cfb, buf, buf, 24); + ideaCfbDestroy(&cfb); + ideaRandInit(&randContext, buf, buf+16); + + f = fopen(globalRandseedName, FOPWBIN); + if (f) { + fwrite(buf, 1, 24, f); + fclose(f); } +} - /* Empty recycled pool. Try a more expensive fresh random byte. */ - if (randcount) /* nonempty random pool--return a very random number */ - return (randpool[--randcount]); - - /* Alas, fresh random pool is empty. Get a pseudorandom byte. - Pseudorandom numbers are risky for cryptographic applications. - Although we will return a pseudorandom byte in the low order byte, - indicate error by making the result negative in the high byte. - */ - /* DEBUGprintf1("\007Warning: random pool empty! "); */ - return ( (pseudorand() & 0xFF) ^ (-1) ); -} /* randombyte */ - - -static short keybuf = 0; /* used only by keypress() and getkey() */ - -boolean keypress(void) /* TRUE iff keyboard input ready */ -{ /* Accumulates random numbers by timing user keystrokes. */ - static short lastkey = 0; /* used to detect autorepeat key sequences */ - static short next_to_lastkey = 0; /* allows a single repeated key */ - -#ifndef USEPCTIMER /* no fast hardware timer available */ - fastcounter++; /* used in lieu of fast hardware timer counter */ -#endif /* ifndef USEPCTIMER */ - - if (keybuf & 0x100) /* bit 8 means keybuf contains valid data */ - return( TRUE ); /* key was hit the last time thru */ - - if (kbhit() == 0) /* keyboard was not hit */ - return( FALSE ); - - keybuf = getch() | 0x100; /* set data latch bit */ - - /* Keyboard was hit. Decide whether to call capturecounter... */ - - /* Guard against typahead buffer defeating fastcounter's randomness. - ** This could be a problem for multicharacter sequences generated - ** by a function key expansion or by the user generating keystrokes - ** faster than our event loop can handle them. Only the last - ** character of a multicharacter sequence will trigger the counter - ** capture. Also, don't let the keyboard's autorepeat feature - ** produce nonrandom counter capture. However, we do allow a - ** single repeated character to trigger counter capture, because - ** many english words have double letter combinations, and it's - ** unlikely a typist would exploit the autorepeat feature to - ** type a simple double letter sequence. - */ - - if (kbhit() == 0) /* nothing in typahead buffer */ - { /* don't capture counter if key repeated */ - if (keybuf != lastkey) - capturecounter(); /* save current random number seed */ - else if (keybuf != next_to_lastkey) /* allow single repeat */ - capturecounter(); - next_to_lastkey = lastkey; - lastkey = keybuf; +/* + * True random bit handling + */ + +/* + * Because these truly random bytes are so unwieldy to accumulate, + * they can be regarded as a precious resource. Unfortunately, + * cryptographic key generation algorithms may require a great many + * random bytes while searching about for large random prime numbers. + * Fortunately, they need not all be truly random. We only need as + * many truly random bits as there are bits in the large prime we + * are searching for. These random bytes can be recycled and modified + * via pseudorandom numbers until the key is generated, without losing + * any of the integrity of randomness of the final key. + * + * The technique used is a pool of random numbers, which bytes are + * taken from successively and, when the end is reached, the pool + * is stirred using an irreversible hash function. Some (64 bytes) + * of the pool is not returned to ensure the sequence is not predictible + * from the values retriefed from trueRandByte(). To be precise, + * MD5Transform is used as a block cipher in CBC mode, and then the + * "key" (i.e. what is usually the material to be hashed) is overwritten + * with some of the just-generated random bytes. + * + * This is implemented in randpool.c; see that file for details. + * + * An estimate of the number of bits of true (Shannon) entropy in the + * pool is kept in trueRandBits. This is incremented when timed + * keystrokes are available, and decremented when bits are explicitly + * consumed for some purpose (such as prime generation) or another. + * + * trueRandFlush is called to obliterate traces of old random bits after + * prime generation is completed. (Primes are the most carefully-guarded + * values in PGP.) + */ + +static unsigned trueRandBits = 0; /* Bits of entropy in pool */ + +/* trueRandPending is bits to add to next accumulation request */ +static unsigned trueRandPending = 0; + +/* + * Destroys already-used random numbers. Ensures no sensitive data + * remains in memory that can be recovered later. This is called + * after RSA key generation, so speed is not critical, but security is. + * RSA key generation takes long enough that interrupts and other + * tasks are likely to have used a measurable and difficult-to-predict + * amount of real time, so there is some virtue in sampling the clocks + * with noise(). + */ +void +trueRandFlush(void) +{ + noise(); + randPoolStir(); /* Destroy evidence of what primes were generated */ + randPoolStir(); + randPoolStir(); + randPoolStir(); /* Make *really* certain */ +} + +/* + * "Consumes" count bits worth of entropy from the true random pool for some + * purpose, such as prime generation. + * + * Note that something like prime generation can end up calling trueRandByte + * more often than is implied by the count passed to trueRandClaim; this + * may happen if the random bit consumer is not perfectly efficient in its + * use of random bits. For example, if a search for a suitable prime fails, + * the easiest thing to do is to get another load of random bits and try + * again. It is perfectly acceptable if these bits are correlated with the + * bits used in the failed attempt, since they are discarded. + */ +void +trueRandConsume(unsigned count) +{ + assert (trueRandBits >= count); + trueRandBits -= count; +} + +/* + * Returns a truly random byte if any are available. It degenerates to + * a pseudorandom value if there are none. It is not an error to call + * this if none are available. For example, it is called when generating + * session keys to add to other sources of cryptographic random numbers. + * + * This forces an accumulation if any extra random bytes are pending. + */ +int +trueRandByte(void) +{ + if (trueRandPending) + trueRandAccum(0); + + return randPoolGetByte(); +} + +/* + * Given an event (typically a keystroke) coded by "event" + * at a random time, add all randomness to the random pool, + * compute a (conservative) estimate of the amount, add it + * to the pool, and return the amount of randomness. + * (The return value is just for informational purposes.) + * + * Double events are okay, but three in a row is considered + * suspiscous and the randomness is counted as 0. + */ +unsigned +trueRandEvent(int event) +{ + static int event1 = 0, event2 = 0; + word32 delta; + unsigned cbits; + + delta = noise(); + randPoolAddBytes((byte *)&event, sizeof(event)); + + if (event == event1 && event == event2) { + cbits = 0; + } else { + event2 = event1; + event1 = event; + + for (cbits = 0; delta; cbits++) + delta >>= 1; + + /* Excessive paranoia? */ + if (cbits > 8) + cbits = 8; } - return( TRUE ); -} /* keypress */ + trueRandBits += cbits; + if (trueRandBits > RANDPOOLBITS) + trueRandBits = RANDPOOLBITS; + + return cbits; +} -short getkey(void) /* Returns data from keyboard (no echo). */ -{ /* Also accumulates random numbers via keypress(). */ - while(! keypress() ); /* loop until key is pressed. */ - return( keybuf &= 0xff); /* clear latch bit 8 */ -} /* getkey */ - - -#define BS 8 /* ASCII backspace */ -#define CR 13 /* ASCII carriage return */ -#define LF 10 /* ASCII linefeed */ - - -int getstring(char *strbuf, int maxlen, boolean echo) -/* Gets string from user, with no control characters allowed. - Also accumulates random numbers by calling getkey(). - maxlen is max length allowed for string. - echo is TRUE iff we should echo keyboard to screen. - Returns null-terminated string in strbuf. -*/ -{ short i; + +/* + * Since getting random bits from the keyboard requires user attention, + * we buffer up requests for them until we can do one big request. + */ +void +trueRandAccumLater(unsigned bitcount) +{ + trueRandPending += bitcount; /* Wow, that was easy! :-) */ +} + +static void flush_input(void); + +/* + * Performs an accumulation of random bits. As long as there are fewer bits + * in the buffer than are needed (the number passed, plus pending bits), + * prompt for more. + */ +void +trueRandAccum(unsigned count) /* Get this many random bits ready */ +{ + int c; +#if defined(MSDOS) || defined(__MSDOS__) + time_t timer; +#endif + + count += trueRandPending; /* Do deferred accumulation now */ + trueRandPending = 0; + + if (count > RANDPOOLBITS) + count = RANDPOOLBITS; + + if (trueRandBits >= count) + return; + + fprintf(stderr, +LANG("\nWe need to generate %u random bits. This is done by measuring the\ +\ntime intervals between your keystrokes. Please enter some random text\ +\non your keyboard until you hear the beep:\n"), count-trueRandBits); + + ttycbreak(); + + do { + /* display counter to show progress */ + fprintf(stderr,"\r%4d ", count-trueRandBits); + fflush(stderr); /* assure screen update */ + + flush_input(); /* If there's no delay, we can't use it */ + c = getch(); /* always wait for input */ +#ifdef MSDOS + if (c == 3) + breakHandler(SIGINT); + if (c == 0) + c = getch() + 256; +#endif + /* Print flag indicating acceptance (or not) */ + putc(trueRandEvent(c) ? '.' : '?' , stderr); + } while (trueRandBits < count); + + fputs("\r 0 *", stderr); + fputs(LANG("\007 -Enough, thank you.\n"), stderr); + +#if defined(MSDOS) || defined(__MSDOS__) + /* Wait until one full second has passed without keyboard input */ + do { + flush_input(); + sleep(1); + } while (kbhit()); +#else + sleep(1); + flush_input(); +#endif + + ttynorm(); +} + +#define BS 8 +#define LF 10 +#define CR 13 +#define DEL 127 + +#ifdef VMS +int putch(int); +#else +#define putch(c) putc(c, stderr) +#endif + +int +getstring(char *strbuf, unsigned maxlen, int echo) +/* Gets string from user, with no control characters allowed. + * Also accumulates random numbers. + * maxlen is max length allowed for string. + * echo is TRUE iff we should echo keyboard to screen. + * Returns null-terminated string in strbuf. + */ +{ + unsigned i; char c; + + ttycbreak(); + +#ifdef AMIGA + aecho = (int)echo; + echo = FALSE; /* echo is done in getch */ +#endif /* AMIGA */ + + fflush(stdout); i=0; - while (TRUE) - { c = getkey(); - if (c==BS) - { if (i) - { if (echo) - { fputc(BS,stderr); - fputc(' ',stderr); - fputc(BS,stderr); + for (;;) { +#ifndef VMS + fflush(stderr); +#endif /* VMS */ + c = getch(); + trueRandEvent(c); +#ifdef VMS + if (c == 25) { /* Control-Y detected */ + ttynorm(); + breakHandler(SIGINT); + } +#endif /* VMS */ +#if defined(MSDOS) || defined (__MSDOS__) + if (c == 3) + breakHandler(SIGINT); +#endif + if (c==BS || c==DEL) { + if (i) { + if (echo) { + putch(BS); + putch(' '); + putch(BS); } i--; } continue; } - if (echo) fputc(c,stderr); - if (c==CR) - { if (echo) fputc(LF,stderr); + if (c < ' ' && c != LF && c != CR) { + putch('\007'); +#if defined(MSDOS) || defined (__MSDOS__) + if (c == 3) + breakHandler(SIGINT); + if (c == 0) + getch(); /* Skip extended key codes */ +#endif + continue; + } + if (echo) + putch(c); + if (c==CR) { + if (echo) + putch(LF); break; } if (c==LF) break; if (c=='\n') break; - if (c<' ') /* any ASCII control character */ - break; strbuf[i++] = c; - if (i>=maxlen) - { fprintf(stderr,"\007*\n"); /* -Enough! */ - while (keypress()) - getkey(); /* clean up any typeahead */ + if (i >= maxlen) { + fputs("\007*\n", stderr); /* -Enough! */ +#if 0 + while (kbhit()) + getch(); /* clean up any typeahead */ +#endif break; } } strbuf[i] = '\0'; /* null termination of string */ - return(i); /* returns string length */ -} /* getstring */ + ttynorm(); -void randaccum(short bitcount) /* Get this many random bits ready */ -/* We will need a series of truly random bits for key generation. - In most implementations, our random number supply is derived from - random keyboard delays rather than a hardware random number - chip. So we will have to ensure we have a large enough pool of - accumulated random numbers from the keyboard. Later, randombyte - will return bytes one at a time from the accumulated pool of - random numbers. For ergonomic reasons, we may want to prefill - this random pool all at once initially. This routine prefills - a pool of random bits. */ -{ short nbytes; - char c; - nbytes = min((bitcount+7)/8,sizeof(randpool)); + return(i); /* returns string length */ +} /* getstring */ - if (randcount < nbytes) /* if we don't have enough already */ - { fprintf(stderr,"\nWe need to generate %d random bytes. This is done by measuring the", - nbytes-randcount); - fprintf(stderr,"\ntime intervals between your keystrokes. Please enter some text on your"); - fprintf(stderr,"\nkeyboard, at least %d nonrepeating keystrokes, until you hear the bell:\n", - (8*(nbytes-randcount)+cbits-1)/cbits); - while (randcount < nbytes) - { c=getkey(); - fputc(c,stderr); - if (c==CR) fputc(LF,stderr); - } - fprintf(stderr,"\007*\n-Enough, thank you.\n"); - while (keypress()) getkey(); /* clean up any typeahead */ - } /* if (randcount < nbytes) */ -} /* randaccum */ +static void +flush_input(void) +{ /* on unix ttycbreak() will flush the input queue */ +#if defined(MSDOS) || defined (__MSDOS__) + while (kbhit()) /* flush typahead buffer */ + getch(); +#endif +}