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