--- pgp/src/random.c 2018/04/24 16:38:27 1.1.1.3 +++ pgp/src/random.c 2018/04/24 16:40:01 1.1.1.5 @@ -10,6 +10,12 @@ such as Unix, VAX/VMS and others. Revised 2 Sep 92 by Peter Gutmann and PRZ to use MD5 to distill high quality randomness down from low-grade random noise. + Revised 25 Feb 93 by Colin Plumb to use MD5 much more for + more secure random numbers. (randstir hacked) + Revised 4 Mar 93 by Colin Plumb to remove the CRUDE and non-USE_MD5 + options, as no platform currently uses them, they make the code + hard to read, and they were suffering bit rot. Also added + NO_ITIMER for the isc port and randaccum_later. This code generates truly random numbers derived from a counter that is incremented continuously while the keyboard is scanned for user input. @@ -25,10 +31,39 @@ bytes accumulated by the user touching the keyboard. **********************************************************************/ +#ifdef UNIX +#include +#include + +#if defined(linux) +/* linux >= 0.99.9 has microsecond resolution gettimeofday() */ +#define USE_GETTIMEOFDAY +#endif + +#ifdef NO_ITIMER /* Some systems lie about itimer */ +#undef ITIMER_REAL +#endif + +#ifndef ITIMER_REAL +#include +#endif +#endif /* UNIX */ + +#if defined(UNIX) || defined(VMS) +#include +#endif + +#include /* for putchar() and printf() */ #include +#ifndef _BSD #include +#endif +#include "system.h" #include "random.h" #include "language.h" + +static long pseudorand(void); /* 31-bit LCG pseudorandom generator */ + #ifdef M_XENIX long time(); #endif @@ -41,12 +76,43 @@ long time(); easier. To use it as the source of random numbers, define PSEUDORANDOM. Warning: Don't do this for actual applications. */ -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 */ +/** + ** Minimal Standard Pseudo-Random Number Generator + ** + ** Author: Fuat C. Baran, Columbia University, 1988 + ** + ** Based on code in "Random Number Generators: Good Ones are Hard to Find", + ** by Stephen K. Park and Keith W. Miller in Communications of the ACM, + ** 31, 10 (Oct. 1988) pp. 1192-1201. + ** + **/ + +/* some constants we need */ +#define A 16807L +#define M 2147483647L /* Mersenne prime 2^31 -1 */ +#define Q 127773L /* M div A (M / A) */ +#define R 2836L /* M mod A (M % A) */ + +static long pseudorand(void) +{ + long hi, lo; +#ifdef DEBUG + static long seed = 1; +#else + static long seed = 0; +#endif + if (!seed || seed == M) +#ifdef UNIX + seed = ((long) getpid() << 16) ^ time(NULL); +#else + seed = ((long) clock() << 16) ^ time(NULL); +#endif + hi = seed / Q; + lo = seed % Q; + if ((seed = A * lo - R * hi) <= 0) + seed += M; + return seed; +} #ifndef PSEUDORANDOM /* use truly random numbers */ @@ -54,24 +120,21 @@ int pseudorand(void) /* #define USEPCTIMER */ /* use fast hardware timer on IBM PC or AT or clone */ /* #define DEBUG */ -/* If operating system shields keyboard event timings from user, then - we can't use any hardware or software timer logic to time events. - This is a messy situation, so we have special logic to handle - it, defining the symbol CRUDE to compile special code. - This may be needed in some multiuser Unix systems, for example. -*/ -#ifdef CRUDE /* No environmental support to capture keyboard event times */ -#undef USEPCTIMER -#endif /* CRUDE */ - -#include /* for putchar() and printf() */ - /* Prototypes for kbhit() (whether the keyboard has been hit) and getch() (like getchar() but no echo, no buffering). Not available under some implementations */ +#if defined(MSDOS) && !defined(__GO32__) +#include +typedef word16 fastcnt_t; +#else +typedef word32 fastcnt_t; +#endif /* !MSDOS || __GO32__ */ -int kbhit( void ); -int getch( void ); +#ifdef VMS +int putch(int); +#else +#define putch(c) putc(c, stderr) +#endif #ifdef DEBUG #define DEBUGprintf1(x) fprintf(stderr,x) @@ -81,23 +144,23 @@ int getch( void ); #define DEBUGprintf2(x,y) #endif - -int randcount = 0 ; /* # of random bytes accumulated in pool */ -static byte randpool[256] = {0} ; /* pool of truly random bytes */ +#define POOLSIZE 256 +static int randcount = 0; /* # of random bytes accumulated in pool */ +static byte randpool[POOLSIZE] = {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 */ +static byte recyclepool[POOLSIZE] = {0} ; /* pool of recycled random bytes */ + +static int accumpending = 0; /* # of random bits to add to next request */ + +static void randstir(byte *pool); /* fastcounter is a free-running counter incremented in main event loop. */ -static unsigned fastcounter = 0; /* not needed if we can use the PC timer. */ -static unsigned lastcounter = 0; +static fastcnt_t fastcounter = 0; /* not needed if we can use the PC timer. */ +static fastcnt_t lastcounter = 0; +static int cbits; static char toofast = 0; /* toofast indicates keystroke rejected because it was typed too fast */ -#ifdef CRUDE -static boolean capturemode = FALSE; -#endif /* CRUDE */ - #ifdef AMIGA int aecho; #endif @@ -113,20 +176,12 @@ int aecho; The randomness transformation is carried out inside capturecounter() when the data is entered, and is transparent to the operation of the rest of the code. - - The use of this randomness-distillation can be turned off by toggling the - following define in case the randomness code needs to be run on a - washing-machine controller or somesuch. */ -#define USE_MD5 /* Turn on MD5 randomization */ - -#ifdef USE_MD5 -void Transform( unsigned long *seedBuffer, unsigned long *data ); -byte seedBuffer[ 64 ]; /* Buffer for MD5 seed value */ -boolean isInitialised = FALSE; /* Whether buffer has been inited */ -byte iv[ 16 ]; /* IV for MD5 transformation */ -#endif /* USE_MD5 */ +#include "md5.h" +static byte seedBuffer[ 64 ]; /* Buffer for MD5 seed value */ +static boolean isInitialised = FALSE; /* Whether buffer has been inited */ +static byte iv[ 16 ]; /* IV for MD5 transformation */ #ifdef USEPCTIMER /* we will use fast hardware timer on IBM PC */ /* #include */ /* function definitions for inp() and outp() */ @@ -224,25 +279,20 @@ extern const long vms_ticks_per_update; #endif /* VMS */ -void capturecounter(void) +static void capturecounter(void) /* Push a fast counter on the random stack. Should be called when ** the user touches a key or clicks the mouse. */ { - int dt, i, j; -#ifndef USE_MD5 - static unsigned int accum = 0; -#endif /* USE_MD5 */ + fastcnt_t dt; +#ifndef MSDOS + byte *random_xtra; /* extra timer info */ +#endif static byte abits = 0; /* number of accumulated bits in accum */ unsigned int accum1; #define cbitsmask ((1 << cbits)-1) -#ifdef CRUDE /* No environmental support to capture keyboard event times. */ - if (!capturemode) - return; /* only captures during randaccum function */ -#endif /* CRUDE */ - /* fastcounter only contains timing information, in the form of a free-running timer, either hardware or software. accum1 contains stuff from fastcounter and other sources, @@ -250,17 +300,11 @@ void capturecounter(void) */ #if defined(USEPCTIMER) /* we will use fast hardware timer on IBM PC */ -#define cbits 8 /* number of bits of counter to capture each time */ fastcounter = pctimer0(); /* capture hardware timer */ -#else -#if defined(CRUDE) /* no fast hardware timer available */ -#define cbits 2 -#else /* not CRUDE */ -#ifndef cbits -#define cbits 4 /* number of bits of counter to capture each time */ -#endif +#endif /* not USEPCTIMER */ + #ifdef VMS -#define cbits 2 /* fewer bits because VMS timer is so slow (100 Hz) */ +#define HW_TIMER 1 /* using hardware timer */ /* Capture fast system timer: */ SYS$GETTIM(vms_clock_bits); #ifdef TEST_COUNTER @@ -269,26 +313,72 @@ void capturecounter(void) /* vms_clock_bits[0] and vms_ticks_per_update are 32-bits each. */ fastcounter = vms_clock_bits[0] / vms_ticks_per_update; #endif /* VMS */ -#endif /* not CRUDE */ -#endif /* not USEPCTIMER */ -#ifndef CRUDE /* keyboard timings are available */ +#ifdef UNIX +#define HW_TIMER 1 /* using hardware timer */ +#ifdef USE_GETTIMEOFDAY + { static struct timeval tv; + gettimeofday(&tv, NULL); + /* divide by 64 (we can at least expect a 60Hz clock) */ + fastcounter = tv.tv_usec / (1000000/64) + tv.tv_sec * 64; + random_xtra = (byte *) &tv; +#define XTRA_BYTES (sizeof(struct timeval)) + } +#else /* !USE_GETTIMEOFDAY */ +#ifdef ITIMER_REAL + { static struct itimerval it; + getitimer(ITIMER_REAL, &it); + if (it.it_value.tv_sec == 0 && it.it_value.tv_usec == 0) + { /* start the timer */ + it.it_value.tv_sec = 100000; + it.it_value.tv_usec = 0; + it.it_interval.tv_sec = 100000; + it.it_interval.tv_usec = 0; + signal(SIGALRM, SIG_IGN); /* just in case.. */ + setitimer(ITIMER_REAL, &it, NULL); + return; + } + /* divide by 64 (we can at least expect a 60Hz clock) */ + fastcounter = 6400000-(it.it_value.tv_usec / (1000000/64) + + it.it_value.tv_sec * 64); + random_xtra = (byte *) &it.it_value; +#define XTRA_BYTES (sizeof(struct timeval)) + } +#else /* !ITIMER_REAL */ + { static struct tms tms; + fastcounter = times(&tms); + random_xtra = (byte *) &tms; +#define XTRA_BYTES (sizeof(struct tms)) + } +#endif /* !ITIMER_REAL */ +#endif /* !USE_GETTIMEOFDAY */ +#endif /* UNIX */ + dt = fastcounter - lastcounter; - if (dt < 0) /* timer rolled over past zero */ - dt = -dt; /* absolute value of time elapsed */ #ifdef TEST_COUNTER - fprintf(stderr,"\n", dt); + fprintf(stderr,"%6lu", dt); +#endif +#ifndef NO_CBIT_STRIP + dt /= 6; /* use 2.5 bits less than the actual count */ +#endif + for (cbits = 0; dt; ++cbits) + dt >>= 1; +#if 0 /* I don't think this is necessary - CP */ + if (cbits > 8) + cbits = 8; #endif - if ( ((unsigned) dt) < (unsigned)(1 << (cbits + 2))) + +#ifdef TEST_COUNTER + fprintf(stderr,"%6u\n", cbits); +#endif + if (cbits <= 0) { toofast++; /* indicate a too-fast keystroke */ return; /* only captures if enough time has passed */ } -#endif /* not CRUDE */ lastcounter = fastcounter; /* latch timer info */ -#ifdef USE_MD5 /* Initialise the MD5 info if necessary */ if( !isInitialised ) /* we probably shouldn't bother */ { memset(seedBuffer, 0, 64); @@ -298,30 +388,29 @@ void capturecounter(void) /* Add the slightly-random data to the MD5 input buffer. Currently we just add a few bytes of environmental noise, but we could mix in - up to 512 bits worth. + up to 512 bits worth. This should be extended in a system-specific + manner. */ seedBuffer[ 0 ] = keybuf; /* actual character user typed */ seedBuffer[ 1 ] = lastcounter & 0xFF; seedBuffer[ 2 ] = lastcounter >> 8; +#ifdef MSDOS accum1 = ( int ) clock(); /* clock ticks */ seedBuffer[ 3 ] = accum1 & 0xFF; seedBuffer[ 4 ] = accum1 >> 8; +#endif +#ifndef USE_GETTIMEOFDAY accum1 = ( int ) time(NULL); /* seconds */ seedBuffer[ 5 ] = accum1 & 0xFF; seedBuffer[ 6 ] = accum1 >> 8; +#endif /* !USE_GETTIMEOFDAY */ +#ifdef XTRA_BYTES /* add some extra "random" stuff */ + memcpy(seedBuffer+16, random_xtra, XTRA_BYTES); +#endif /* The preceding "noise quantum" has only cbits worth of randomness. */ + /* Spread it uniformly across the entire pool */ - /* Now use MD5 to diffuse the randomness in these bits over the random - byte pool, raising the salinity of randomness in the pool. The - transformation is carried out by "encrypting" the data in CFB mode - with MD5 as the block cipher */ - for(i = 0; i < sizeof(randpool); i += 16) - { - Transform((unsigned long *) iv, (unsigned long *) seedBuffer); - for(j = 0; j < 16; j++) - randpool[i+j] ^= iv[j]; - memcpy(iv, randpool+i, 16); - } + randstir(randpool); /* Now the somewhat dubious bit: In order to make this fit in with @@ -329,10 +418,6 @@ void capturecounter(void) of a high-water mark in the buffer. This is actually reasonably realistic, since it keeps a count of what percentage of the full buffer is random enough-- measuring the "molarity" of solution. - However when it comes time to re-randomize the buffer in - randombyte(), it would probably be better to use the above - transformation than the existing randombyte() code. I've left it - as is to keep it as compatible as possible. */ abits += cbits; /* Update count of bits of randomness */ @@ -342,27 +427,6 @@ void capturecounter(void) randcount++; /* not a byte counter-- now a molarity of randomness */ abits -= 8; } -#else /* not USE_MD5 */ - /* combine several sources to attempt maximum randomness... */ - accum1 = keybuf; /* actual keystroke */ - accum1 += lastcounter; /* add latched timer info */ - accum1 += clock(); /* clock ticks */ - accum1 += time(NULL); /* seconds */ - - accum1 ^= (accum1 >> cbits); /* Fold upper and lower bits */ - - /* slide some new bits into the bit accumulator: */ - accum = (accum << cbits) | (unsigned int) (accum1 & cbitsmask); - abits += cbits; - while (abits >= 8) /* another byte's worth of bits accumulated */ - { if (randcount < sizeof(randpool)) - /* take lower byte of accum */ - randpool[randcount++] = accum; - abits -= 8; - accum >>= 8; - } -#endif /* not USE_MD5 */ -#undef cbitsmask } /* capturecounter */ @@ -378,13 +442,30 @@ void capturecounter(void) */ -static void randstir(void) -/* Stir up the recycled random number bin, via a pseudorandom generator */ +static void randstir(byte *pool) +/* Stir up the recycled random number bin, via a pseudorandom generator + Any truly random bytes stored into the seedBuffer are hashed into the + pool, and then destroyed for security reasons. */ { int i; - i = recyclecount; - while (i--) - recyclepool[i] ^= (byte) pseudorand(); - DEBUGprintf2(" Stirring %d recycled bytes. ",recyclecount); + int j; + /* Now use MD5 to diffuse the randomness in these bits over the random + byte pool, raising the salinity of randomness in the pool. The + transformation is carried out by "encrypting" the data in CFB mode + with MD5 as the block cipher */ + for(i = 0; i < POOLSIZE; i += 16) + { + Transform((UINT4 *) iv, (UINT4 *) seedBuffer); + for(j = 0; j < 16; j++) + pool[i+j] ^= iv[j]; + memcpy(iv, pool+i, 16); + } +/* CFB encryption is reversible; if we want the stirring operation to + be strictly one-way, we must destroy the key. The operation + accomplishes that, and increases the end-to-beginning feedback + in randstir(), in an attempt to make all bytes depend on all + other bytes. */ + memcpy(seedBuffer, pool+POOLSIZE-sizeof(seedBuffer), + sizeof(seedBuffer)); } /* randstir */ @@ -399,66 +480,98 @@ short randload(short bitcount) while (bytecount--) recyclepool[recyclecount++] = randpool[--randcount]; DEBUGprintf2("\nAllocating %d recycleable random bytes. ",recyclecount); + randstir(recyclepool); + recyclecount = sizeof(recyclepool); 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; - memset(seedBuffer, 0, 64); - memset(iv, 0, 16); +{ +/* We do not actually destroy the random bytes (which would be somewhat + wasteful); we just stir them so that they are irretrievable. This + assumes that MD5 is truly one-way. */ + randstir(recyclepool); + recyclecount = 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. -*/ -{ +short try_randombyte(void) +/* Returns a truly random byte if any are available, or -1 if none. + * it is not an error to call this if none are available. For example, + * make_random_ideakey calls it to add to its other sources of pseudo-random + * noise. + */ +{ /* 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]); + { + byte b; + b = recyclepool[--recyclecount]; + if (!recyclecount) /* Used them all up? */ + randstir(recyclepool); /* Refresh recycled pool */ + return b; } /* 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 bad 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. + /* No, all is for naught. Return -1. */ + return -1; +} + +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. +*/ +{ + short r; + + r = try_randombyte(); + if (r >= 0) + return r; + + /* Oops! Random pool empty. Were there some unsatisifed deferred + accumulation requests? */ + randaccum(0); + r = try_randombyte(); + if (r >= 0) + return r; + + /* Alas, fresh random pool is truly empty. Complain, and return + a pseudorandom byte. Pseudorandom numbers are bad 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! "); */ + fprintf(stderr, " \007WARNING: Random pool empty! "); return ( (pseudorand() & 0xFF) ^ (-1) ); } /* randombyte */ -boolean keypress(void) /* TRUE iff keyboard input ready */ +static boolean keypress(void) /* TRUE iff keyboard input ready */ { /* Accumulates random numbers by timing user keystrokes. */ -#ifndef CRUDE 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 */ +#ifndef HW_TIMER /* no fast hardware timer available */ fastcounter++; /* used in lieu of fast hardware timer counter */ -#endif /* ifndef USEPCTIMER */ +#endif /* ifndef HW_TIMER */ if (keybuf & 0x100) /* bit 8 means keybuf contains valid data */ return( TRUE ); /* key was hit the last time thru */ + /* + * If HW_TIMER is defined we don't need a busy loop, so keypress + * waits for a key and will always return TRUE. + */ +#ifndef HW_TIMER if (kbhit() == 0) /* keyboard was not hit */ return( FALSE ); +#endif keybuf = getch() | 0x100; /* set data latch bit */ @@ -479,7 +592,9 @@ boolean keypress(void) /* TRUE iff keybo ** against other reasons for characters coming in too fast. */ +#ifndef HW_TIMER if (kbhit() == 0) /* nothing in typahead buffer */ +#endif { /* don't capture counter if key repeated */ if (keybuf != lastkey) capturecounter(); /* read random noise from environment */ @@ -489,20 +604,14 @@ boolean keypress(void) /* TRUE iff keybo lastkey = keybuf; } return( TRUE ); -#else /* CRUDE */ - return(FALSE); -#endif } /* keypress */ -short getkey(void) /* Returns data from keyboard (no echo). */ +static short getkey(void) /* Returns data from keyboard (no echo). */ { /* Also accumulates random numbers via keypress(). */ -#ifndef CRUDE - while(! keypress() ); /* loop until key is pressed. */ + while(! keypress() ) /* loop until key is pressed. */ + ; return( keybuf &= 0xff); /* clear latch bit 8 */ -#else - return(keybuf = getch() & 0xff); -#endif } /* getkey */ @@ -511,6 +620,14 @@ short getkey(void) /* Returns data from #define LF 10 /* ASCII linefeed */ #define DEL 0177 /* ASCII delete */ +/* Since getting random bits from the keyboard requires user attention, + we buffer up requests for them until we can do one big request. */ + +void randaccum_later(short bitcount) +{ + accumpending += bitcount; /* Wow, that was easy! :-) */ +} + /* 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 @@ -522,21 +639,15 @@ short getkey(void) /* Returns data from prefills a pool of random bits. */ -#if defined(UNIX) || defined(AMIGA) || defined(VMS) -#define NEEDBREAK -void ttycbreak(); -void ttynorm(); -#endif - -#ifndef CRUDE /* We can measure keyboard event times accurately. */ - void randaccum(short bitcount) /* Get this many random bits ready */ { short nbytes; - char c; - int col = 0; +#ifndef HW_TIMER unsigned long timer; +#endif int fasts_rejected = 0; /* number of too-fast keystrokes */ + bitcount += accumpending; /* Do deferred accumulation now */ + accumpending = 0; nbytes = min((bitcount+7)/8,sizeof(randpool)); fasts_rejected = 0; /* number of too-fast keystrokes */ toofast = 0; /* clear too-fast latch */ @@ -544,9 +655,8 @@ void randaccum(short bitcount) /* Get th if (randcount < nbytes) /* if we don't have enough already */ { fprintf(stderr, PSTR("\nWe need to generate %d random bytes. This is done by measuring the\ -\ntime intervals between your keystrokes. Please enter some text on your\ -\nkeyboard, at least %d nonrepeating keystrokes, until you hear the beep:\n"), - nbytes-randcount, (8*(nbytes-randcount)+cbits-1)/cbits); +\ntime intervals between your keystrokes. Please enter some random text\ +\non your keyboard until you hear the beep:\n"), nbytes-randcount); #ifdef NEEDBREAK ttycbreak(); #endif @@ -554,9 +664,11 @@ PSTR("\nWe need to generate %d random by while (randcount < nbytes) { +#ifndef TEST_COUNTER fprintf(stderr,"\r%3d ",nbytes-randcount); +#endif fflush(stderr); - c=getkey(); + getkey(); if (toofast) { fasts_rejected++; /* keep score */ toofast = 0; /* reset latch */ @@ -572,6 +684,9 @@ PSTR("\nWe need to generate %d random by fprintf(stderr,PSTR("(Ignored %d keystrokes that were typed too fast.)\n"), fasts_rejected); +#ifdef HW_TIMER /* keypress() would block if using hardware timer */ + sleep(1); +#else /* Clean up typeahead for at least 1 full second... */ timer = time(NULL) + 1; /* need at least 1 second of quiet */ while ((unsigned long) time(NULL) <= timer) @@ -580,6 +695,7 @@ PSTR("\nWe need to generate %d random by timer = time(NULL) + 1; } } +#endif #ifdef NEEDBREAK ttynorm(); @@ -587,62 +703,6 @@ PSTR("\nWe need to generate %d random by } } /* randaccum */ -#endif /* not CRUDE */ - - -#ifdef CRUDE /* We cannot measure keyboard event times accurately. */ - -/* If we can't measure keyboard event timings, use the actual keys - typed as the source of randomness. - - This is a really lousy way to make random numbers. We will only use - this method as a last resort, only if this machine does not allow - keyboard events to be timed accurately. It's better than nothing. - The other randaccum function listed above is much better, if the - CRUDE symbol is undefined and the environment will support it. - - We have improved this scheme somewhat by using a good hashing - function (MD5) on the user input before capturing it in the - random pool. This is done in function capturecounter(). -*/ - -void randaccum(short bitcount) /* Get this many random bits ready */ -{ short nbytes; - char c, flushbuf[80]; - nbytes = min((bitcount+7)/8,sizeof(randpool)); - - randcount = 0; /* start with nothing in pool. */ - capturemode = TRUE; /* enable capture of random keys */ - fastcounter += time(0); /* start with time of day, if available */ - - fprintf(stderr,PSTR("\nWe need to generate %d random bytes.\ -\nPlease enter at least %d random keystrokes, as random\ -\nas you can possibly make them.\n"), - nbytes-randcount, (8*(nbytes-randcount)+cbits-1)/cbits); - while (randcount < nbytes) - { c=getkey(); - capturecounter(); - } - /* - * CRUDE mode must work in normal tty mode, so we can't - * use keypress() to flush input. - */ -#ifdef AMIGA - while(keypress()) getch(); -#else - fgets(flushbuf, sizeof(flushbuf), stdin); -#endif - fprintf(stderr,PSTR("\007 -Enough, thank you.\n")); - - capturemode = FALSE; /* don't capture any more keys */ - -#ifdef NEEDBREAK - ttynorm(); -#endif -} /* randaccum */ - -#endif /* CRUDE */ - int getstring(char *strbuf, int maxlen, boolean echo) /* Gets string from user, with no control characters allowed. @@ -663,26 +723,35 @@ int getstring(char *strbuf, int maxlen, fflush(stdout); i=0; while (TRUE) - { fflush(stderr); + { +#ifndef VMS + fflush(stderr); +#endif /* VMS */ c = getkey(); +#ifdef VMS + if (c == 25) { /* Control-Y detected */ + ttynorm(); + breakHandler(SIGINT); + } +#endif /* VMS */ if (c==BS || c==DEL) { if (i) { if (echo) - { fputc(BS,stderr); - fputc(' ',stderr); - fputc(BS,stderr); + { putch(BS); + putch(' '); + putch(BS); } i--; } continue; } if (c < ' ' && c != LF && c != CR) - { putc('\007', stderr); + { putch('\007'); continue; } - if (echo) fputc(c,stderr); + if (echo) putch(c); if (c==CR) - { if (echo) fputc(LF,stderr); + { if (echo) putch(LF); break; } if (c==LF) @@ -707,15 +776,11 @@ int getstring(char *strbuf, int maxlen, #endif /* ifndef PSEUDORANDOM */ -void flush_input() -{ -#ifdef NEEDBREAK - ttycbreak(); -#endif +void flush_input(void) +{ /* on unix ttycbreak() will flush the input queue */ +#ifndef HW_TIMER while (keypress()) /* flush typahead buffer */ getkey(); -#ifdef NEEDBREAK - ttynorm(); #endif }