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

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.  
        !             4:        Revised Jul 88 by PRZ and again Dec 88 by Allan Hoeltje
        !             5:                to use IBM PC 8253 timer0 for a faster counter.
        !             6:        Revised Apr 89 by PRZ to recycle random bytes.
        !             7:        Last revised 15 Dec 90 by PRZ.
        !             8: 
        !             9:        This code generates truly random numbers derived from a counter that is 
        !            10:        incremented continuously while the keyboard is scanned for user input.
        !            11:        Every time the user touches a key, the least significant bits of the 
        !            12:        counter are pushed on a stack.  Later, this supply of random bytes can
        !            13:        be popped off the stack by applications requiring stochastic numbers.
        !            14:        Cryptographic applications require this kind of randomness.
        !            15: 
        !            16:        The only requirement to make this work is that keypress must be called 
        !            17:        frequently, and/or getkey must be called to read the keyboard.  
        !            18: 
        !            19:        Note that you can only get as many random bytes as the number of 
        !            20:        bytes accumulated by the user touching the keyboard.
        !            21: **********************************************************************/
        !            22: 
        !            23: #include       <stdio.h>       /* for putchar() and printf() */
        !            24: #include       <conio.h>       /* for kbhit() and getch() */
        !            25: #include       "random.h"
        !            26: 
        !            27: /* #define USEPCTIMER  /* use fast hardware timer on IBM PC or AT or clone */
        !            28: /* #define DEBUG */
        !            29: 
        !            30: #ifdef DEBUG
        !            31: #define DEBUGprintf1(x) fprintf(stderr,x)
        !            32: #define DEBUGprintf2(x,y) fprintf(stderr,x,y)
        !            33: #else
        !            34: #define DEBUGprintf1(x)
        !            35: #define DEBUGprintf2(x,y)
        !            36: #endif
        !            37: 
        !            38: 
        !            39: static int randseed=0; /* used only by pseudorand() function. */
        !            40: int pseudorand(void)
        !            41: /*     Home-grown 16-bit LCG pseudorandom generator. */
        !            42: {      randseed = (randseed*31421 + 6927) & 0xffff;
        !            43:        return (randseed);
        !            44: }      /* pseudorand */
        !            45: 
        !            46: 
        !            47: int randcount = 0 ;            /* # of random bytes accumulated in pool */
        !            48: static byte randpool[256] = {0} ;      /* pool of truly random bytes */
        !            49: static int recyclecount = 0 ;  /* # of recycled random bytes accumulated */
        !            50: static byte recyclepool[256] = {0} ; /* pool of recycled random bytes */
        !            51: static int recycleptr = 0;     /* points to next byte to grab in recyclepool */
        !            52: 
        !            53: /* fastcounter is a free-running counter incremented in main event loop */
        !            54: static byte fastcounter = 0;   /* not needed if we can use the PC timer. */
        !            55: 
        !            56: 
        !            57: #ifdef USEPCTIMER      /* we will use fast hardware timer on IBM PC */
        !            58: /* #include <conio.h>  /* function definitions for inp() and outp() */
        !            59: /* outp() and inp() works only for Microsoft C for IBM PC or AT */
        !            60: /* timer0 on 8253-5 on IBM PC or AT tics every .84 usec. */
        !            61: #define timer0         0x40    /* 8253 timer 0 port */
        !            62: #define timercntl      0x43    /* 8253 control register */
        !            63: #define timer0rwl      0x00    /* read lo/hi bytes of cntr 2 with latch */
        !            64: #define timer0rnl      0x30    /* read lo/hi bytes of cntr 2 w/o latch */
        !            65: 
        !            66: static byte latched_hitimer = 0; /* captured by keyboard ISR */
        !            67: static byte latched_lotimer = 0; /* captured by keyboard ISR */
        !            68: /* when kbisr captures timer, timer_latched is set. */
        !            69: static boolean timer_latched = FALSE;
        !            70: 
        !            71: static void kbisr(void)        /* Keyboard Interrupt Service Routine (ISR) */
        !            72: /*
        !            73:        kbisr should be called on the way into, or on the way out of,
        !            74:        or from within the DOS keyboard ISR, as long as it gets called
        !            75:        at the time of a keyboard interrupt.  Assumes that the real
        !            76:        DOS keyboard ISR captures the keystroke in the normal way.
        !            77:        Only the hardware timer counter is captured by the kbisr routine,
        !            78:        leaving the actual keystroke capture to the normal DOS keyboard ISR.
        !            79:        We indicate that a timer capture has taken place by setting 
        !            80:        timer_latched.
        !            81: 
        !            82:        NOTE: WE STILL NEED TO FIND A WAY to connect this subroutine with the 
        !            83:        normal keyboard ISR, so that kbisr gets called when there's a keyboard 
        !            84:        interrupt.
        !            85: */
        !            86: {      outp(timercntl,timer0rwl);
        !            87:        latched_lotimer = inp(timer0);
        !            88:        latched_hitimer = inp(timer0);
        !            89:        timer_latched = TRUE;
        !            90: }      /* kbisr */
        !            91: 
        !            92: static unsigned short pctimer0(void)
        !            93: {
        !            94: /*     Reads and returns the hardware 8253 timer0 on the PC or AT
        !            95: **     or clone, shifted right 1 bit.
        !            96: **
        !            97: **     DO NOT SET THE HARDWARE COUNTER TO ZERO. It is already initialized
        !            98: **     by the system to be used by the clock.  It is set up in mode 3
        !            99: **     (square wave rate generator) and counts down by 2 from 0 (0xFFFF+1)
        !           100: **     to produce an 18.2 Hz square wave.  We may, however, READ the
        !           101: **     lo and hi bytes without causing any problems.  BUT just
        !           102: **     remember that the lo byte will always be even (since it is
        !           103: **     counting by two).
        !           104: **
        !           105: **     Note that we can not use counter 1 since it is tied to the
        !           106: **     dynamic RAM refresh hardware.  Counter 2 is tied to the 8255
        !           107: **     PPI chip to do things like sound.  Though it would be safe to
        !           108: **     use counter 2 it is not desirable since we would have to turn
        !           109: **     the speaker on in order to make the timer count!  Normally one
        !           110: **     sets counter 2 to mode 3 (square wave generator) to sound the
        !           111: **     speaker.  You can set mode 2 (pulse generator) and the speaker
        !           112: **     hardly makes any sound at all, a click when you turn it on and
        !           113: **     a click when you turn it off.  Counter 0 should be safe if
        !           114: **     we only read the counter bytes.
        !           115: **
        !           116: **     WARNING:  To use the hardware timer the way it really should be
        !           117: **     used, we ought to capture it via a keyboard interrupt service
        !           118: **     routine (ISR).  Otherwise, we may experience weaknesses in randomness
        !           119: **     due to harmonic relationships between the hardware counter frequency
        !           120: **     and the keyboard software polling frequency.  Unfortunately, this
        !           121: **     implementation does not currently use keyboard interrupts to
        !           122: **     capture the counter.  This is not a problem if we don't use the
        !           123: **     hardware counter, but instead use the software counter fastcounter.
        !           124: **     Thus, the hardware counter should not be used at all, unless we
        !           125: **     support it with an ISR.
        !           126: */
        !           127:        unsigned short t ;
        !           128:        /* See if timer has been latched by kbisr(). */
        !           129:        if (!timer_latched) /* The timer was not already latched. */
        !           130:                kbisr();        /* latch timer */
        !           131:        /* return latched timer and clear latch */
        !           132:        t = (   (((unsigned short) latched_hitimer) << 8) |
        !           133:                 ((unsigned short) latched_lotimer)
        !           134:                ) >> 1 ;
        !           135:        timer_latched = FALSE;
        !           136:        return (t) ;
        !           137: }      /* pctimer0 */
        !           138: 
        !           139: #endif /* ifdef USEPCTIMER */
        !           140: 
        !           141: 
        !           142: void capturecounter(void)
        !           143: /*     Push a fast counter on the random stack.  Should be called when
        !           144: **     the user touches a key or clicks the mouse.
        !           145: */
        !           146: {
        !           147:        static unsigned int accum = 0;
        !           148:        static byte abits = 0;  /* number of accumulated bits in accum */
        !           149: 
        !           150: #ifdef USEPCTIMER      /* we will use fast hardware timer on IBM PC */
        !           151: #define cbits 8                /* number of bits of counter to capture each time */
        !           152:        fastcounter += pctimer0();
        !           153: #else                  /* no fast hardware timer available */
        !           154: #define cbits 4                /* number of bits of counter to capture each time */
        !           155: #endif /* ifdef USEPCTIMER */
        !           156: #define cbitsmask ((1 << cbits)-1)
        !           157: 
        !           158:        accum = (accum << cbits) | (unsigned int) (fastcounter & cbitsmask);
        !           159:        abits += cbits;
        !           160:        while (abits >= 8) 
        !           161:        {       if (randcount < sizeof(randpool))
        !           162:                        /* take lower byte of accum */
        !           163:                        randpool[randcount++] = accum;
        !           164:                abits -= 8;
        !           165:                accum >>= 8;
        !           166:        }
        !           167:        fastcounter = 0;
        !           168: #undef cbitsmask
        !           169: }      /* capturecounter */
        !           170: 
        !           171: 
        !           172: /* Because these truly random bytes are so unwieldy to accumulate,
        !           173:    they can be regarded as a precious resource.  Unfortunately,
        !           174:    cryptographic key generation algorithms may require a great many
        !           175:    random bytes while searching about for large random prime numbers.
        !           176:    Fortunately, they need not all be truly random.  We only need as
        !           177:    many truly random bytes as there are bytes in the large prime we
        !           178:    are searching for.  These random bytes can be recycled and modified
        !           179:    via pseudorandom numbers until the key is generated, without losing
        !           180:    any of the integrity of randomness of the final key.
        !           181: */
        !           182: 
        !           183: 
        !           184: static void randstir(void)
        !           185: /* Stir up the recycled random number bin, via a pseudorandom generator */
        !           186: {      int i;
        !           187:        i = recyclecount;
        !           188:        while (i--)
        !           189:                recyclepool[i] ^= (byte) pseudorand();
        !           190:        DEBUGprintf2(" Stirring %d recycled bytes. ",recyclecount);
        !           191: }      /* randstir */
        !           192: 
        !           193: 
        !           194: short randload(short bitcount)
        !           195: /*     Flushes stale recycled random bits and copies a fresh supply of raw 
        !           196:        random bits from randpool to recyclepool.  Returns actual number of 
        !           197:        bits transferred.  Formerly named randrecycle. */
        !           198: {      int bytecount;
        !           199:        bytecount = (bitcount+7)/8;
        !           200:        bytecount = min(bytecount,randcount);
        !           201:        randflush();    /* reset recyclecount, discarding recyclepool */
        !           202:        while (bytecount--)
        !           203:                recyclepool[recyclecount++] = randpool[--randcount];
        !           204:        DEBUGprintf2("\nAllocating %d recycleable random bytes. ",recyclecount);
        !           205:        return(recyclecount*8);
        !           206: }      /* randload */
        !           207: 
        !           208: 
        !           209: void randflush(void)   /* destroys pool of recycled random numbers */
        !           210: /* Ensures no sensitive data remains in memory that can be recovered later. */
        !           211: {      recyclecount = sizeof (recyclepool);
        !           212:        while (recyclecount)
        !           213:                recyclepool[--recyclecount]=0;
        !           214:        /* recyclecount is left at 0 */
        !           215:        recycleptr = 0;
        !           216: }      /* randflush */
        !           217: 
        !           218: 
        !           219: short randombyte(void)
        !           220: /*     Returns truly random byte from pool, or a pseudorandom value
        !           221: **     if pool is empty.  It is recommended that the caller check
        !           222: **     the value of randcount before calling randombyte.
        !           223: */
        !           224: {      
        !           225:        /* First try to get a cheap recycled random byte, if there are any. */
        !           226:        if (recyclecount)       /* nonempty recycled pool */
        !           227:        {       if (++recycleptr >= recyclecount)       /* ran out? */
        !           228:                {       recycleptr = 0; /* ran out of recycled random numbers */
        !           229:                        randstir();     /* stir up recycled bits */
        !           230:                }
        !           231:                return (recyclepool[recycleptr]);
        !           232:        }
        !           233: 
        !           234:        /* Empty recycled pool.  Try a more expensive fresh random byte. */
        !           235:        if (randcount)  /* nonempty random pool--return a very random number */
        !           236:                return (randpool[--randcount]);
        !           237: 
        !           238:        /* Alas, fresh random pool is empty.  Get a pseudorandom byte.
        !           239:           Pseudorandom numbers are risky for cryptographic applications.
        !           240:           Although we will return a pseudorandom byte in the low order byte,
        !           241:           indicate error by making the result negative in the high byte.
        !           242:        */
        !           243:        /* DEBUGprintf1("\007Warning: random pool empty! "); */
        !           244:        return ( (pseudorand() & 0xFF) ^ (-1) );
        !           245: }      /* randombyte */
        !           246: 
        !           247: 
        !           248: static short keybuf = 0;       /* used only by keypress() and getkey() */
        !           249: 
        !           250: boolean keypress(void) /* TRUE iff keyboard input ready */
        !           251: {      /* Accumulates random numbers by timing user keystrokes. */
        !           252:        static short lastkey = 0; /* used to detect autorepeat key sequences */
        !           253:        static short next_to_lastkey = 0; /* allows a single repeated key */
        !           254: 
        !           255: #ifndef USEPCTIMER     /* no fast hardware timer available */
        !           256:        fastcounter++;  /* used in lieu of fast hardware timer counter */
        !           257: #endif /* ifndef USEPCTIMER */
        !           258: 
        !           259:        if (keybuf & 0x100)     /* bit 8 means keybuf contains valid data */
        !           260:                return( TRUE ); /* key was hit the last time thru */
        !           261: 
        !           262:        if (kbhit() == 0)       /* keyboard was not hit */
        !           263:                return( FALSE );
        !           264: 
        !           265:        keybuf = getch() | 0x100; /* set data latch bit */
        !           266: 
        !           267:        /* Keyboard was hit.  Decide whether to call capturecounter... */
        !           268: 
        !           269:        /*  Guard against typahead buffer defeating fastcounter's randomness.
        !           270:        **  This could be a problem for multicharacter sequences generated
        !           271:        **  by a function key expansion or by the user generating keystrokes
        !           272:        **  faster than our event loop can handle them.  Only the last 
        !           273:        **  character of a multicharacter sequence will trigger the counter
        !           274:        **  capture.  Also, don't let the keyboard's autorepeat feature
        !           275:        **  produce nonrandom counter capture.  However, we do allow a 
        !           276:        **  single repeated character to trigger counter capture, because
        !           277:        **  many english words have double letter combinations, and it's 
        !           278:        **  unlikely a typist would exploit the autorepeat feature to
        !           279:        **  type a simple double letter sequence.
        !           280:        */
        !           281: 
        !           282:        if (kbhit() == 0)       /* nothing in typahead buffer */
        !           283:        {       /* don't capture counter if key repeated */
        !           284:                if (keybuf != lastkey)
        !           285:                        capturecounter(); /* save current random number seed */
        !           286:                else if (keybuf != next_to_lastkey) /* allow single repeat */
        !           287:                        capturecounter();
        !           288:                next_to_lastkey = lastkey;
        !           289:                lastkey = keybuf;
        !           290:        }
        !           291:        return( TRUE );
        !           292: }      /* keypress */
        !           293: 
        !           294: 
        !           295: short getkey(void)     /* Returns data from keyboard (no echo). */
        !           296: {      /* Also accumulates random numbers via keypress(). */
        !           297:        while(! keypress() );           /* loop until key is pressed. */
        !           298:        return( keybuf &= 0xff);        /* clear latch bit 8 */
        !           299: }      /* getkey */
        !           300: 
        !           301: 
        !           302: #define BS 8   /* ASCII backspace */
        !           303: #define CR 13  /* ASCII carriage return */
        !           304: #define LF 10  /* ASCII linefeed */
        !           305: 
        !           306: 
        !           307: int getstring(char *strbuf, int maxlen, boolean echo)
        !           308: /*     Gets string from user, with no control characters allowed.
        !           309:        Also accumulates random numbers by calling getkey().
        !           310:        maxlen is max length allowed for string.
        !           311:        echo is TRUE iff we should echo keyboard to screen.
        !           312:        Returns null-terminated string in strbuf. 
        !           313: */
        !           314: {      short i;
        !           315:        char c;
        !           316:        i=0;
        !           317:        while (TRUE)
        !           318:        {       c = getkey();
        !           319:                if (c==BS) 
        !           320:                {       if (i) 
        !           321:                        {       if (echo) 
        !           322:                                {       fputc(BS,stderr);
        !           323:                                        fputc(' ',stderr);
        !           324:                                        fputc(BS,stderr);
        !           325:                                }
        !           326:                                i--;
        !           327:                        }
        !           328:                        continue;
        !           329:                }
        !           330:                if (echo) fputc(c,stderr);
        !           331:                if (c==CR) 
        !           332:                {       if (echo) fputc(LF,stderr);
        !           333:                        break;
        !           334:                }
        !           335:                if (c==LF)
        !           336:                        break;
        !           337:                if (c=='\n')
        !           338:                        break;
        !           339:                if (c<' ')      /* any ASCII control character */
        !           340:                        break;
        !           341:                strbuf[i++] = c;
        !           342:                if (i>=maxlen) 
        !           343:                {       fprintf(stderr,"\007*\n");      /* -Enough! */
        !           344:                        while (keypress())
        !           345:                                getkey();       /* clean up any typeahead */
        !           346:                        break;
        !           347:                }
        !           348:        }
        !           349:        strbuf[i] = '\0';       /* null termination of string */
        !           350:        return(i);              /* returns string length */
        !           351: }      /* getstring */
        !           352: 
        !           353: 
        !           354: void randaccum(short bitcount) /* Get this many random bits ready */
        !           355: /* We will need a series of truly random bits for key generation.
        !           356:    In most implementations, our random number supply is derived from
        !           357:    random keyboard delays rather than a hardware random number
        !           358:    chip.  So we will have to ensure we have a large enough pool of
        !           359:    accumulated random numbers from the keyboard.  Later, randombyte
        !           360:    will return bytes one at a time from the accumulated pool of
        !           361:    random numbers.  For ergonomic reasons, we may want to prefill
        !           362:    this random pool all at once initially.  This routine prefills
        !           363:    a pool of random bits. */
        !           364: {      short nbytes;
        !           365:        char c;
        !           366:        nbytes = min((bitcount+7)/8,sizeof(randpool));
        !           367: 
        !           368:        if (randcount < nbytes) /* if we don't have enough already */
        !           369:        {       fprintf(stderr,"\nWe need to generate %d random bytes.  This is done by measuring the",
        !           370:                        nbytes-randcount);
        !           371:                fprintf(stderr,"\ntime intervals between your keystrokes.  Please enter some text on your");
        !           372:                fprintf(stderr,"\nkeyboard, at least %d nonrepeating keystrokes, until you hear the bell:\n",
        !           373:                        (8*(nbytes-randcount)+cbits-1)/cbits);
        !           374:                while (randcount < nbytes) 
        !           375:                {       c=getkey();
        !           376:                        fputc(c,stderr);
        !           377:                        if (c==CR) fputc(LF,stderr);
        !           378:                }
        !           379:                fprintf(stderr,"\007*\n-Enough, thank you.\n");
        !           380:                while (keypress()) getkey();    /* clean up any typeahead */
        !           381:        }       /* if (randcount < nbytes) */
        !           382: }      /* randaccum */
        !           383: 

unix.superglobalmegacorp.com

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