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

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: 

unix.superglobalmegacorp.com

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