Annotation of pgp/src/random.c, revision 1.1.1.3

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.