Annotation of pgp/src/noise.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Get environmental noise.
                      3:  *
                      4:  * (c) Copyright 1990-1994 by Philip Zimmermann.  All rights reserved.
                      5:  * The author assumes no liability for damages resulting from the use
                      6:  * of this software, even if the damage results from defects in this
                      7:  * software.  No warranty is expressed or implied.
                      8:  *
                      9:  * Note that while most PGP source modules bear Philip Zimmermann's
                     10:  * copyright notice, many of them have been revised or entirely written
                     11:  * by contributors who frequently failed to put their names in their
                     12:  * code.  Code that has been incorporated into PGP from other authors
                     13:  * was either originally published in the public domain or is used with
                     14:  * permission from the various authors.
                     15:  *
                     16:  * PGP is available for free to the public under certain restrictions.
                     17:  * See the PGP User's Guide (included in the release package) for
                     18:  * important information about licensing, patent restrictions on
                     19:  * certain algorithms, trademarks, copyrights, and export controls.
                     20:  *
                     21:  * Written by Colin Plumb.
                     22:  */
                     23: 
                     24: 
                     25: #ifdef UNIX
                     26: #include <sys/types.h>
                     27: #include <sys/time.h>  /* For gettimeofday() */
                     28: #include <sys/times.h> /* for times() */
                     29: #include <stdlib.h>    /* For qsort() */
                     30: 
                     31: #endif /* UNIX */
                     32: 
                     33: #include <time.h>
                     34: #include "usuals.h"
                     35: #include "randpool.h"
                     36: #include "noise.h"
                     37: 
                     38: /* Some machines just don't have clock_t */
                     39: #if defined(sun) && defined(i386)
                     40: typedef long clock_t;
                     41: #endif
                     42: 
                     43: #if defined(MSDOS) || defined(__MSDOS__)
                     44: 
                     45: /* Use IBM PC hardware timer (1.19 MHz) */
                     46: 
                     47: #include <conio.h>     /* for inp() and outp() */
                     48: 
                     49: /* timer0 on 8253-5 on IBM PC or AT tics every .84 usec. */
                     50: #define timer0         0x40    /* 8253 timer 0 port */
                     51: #define timercntl      0x43    /* 8253 control register */
                     52: 
                     53: /*
                     54:  * On an IBM PC, timer 0 ticks every .84 usec.  It counts down
                     55:  * from 65536 by twos, toggling its output line after each
                     56:  * step.  On an original IBM PC, we can thus only get 15 bits
                     57:  * of the timer.  On a PC-AT or later, with an 8284 timer chip,
                     58:  * we can get all 16 bits by reading the status, which has the
                     59:  * state of the output bit in bit 7, and is effectively the
                     60:  * high bit of the counter.
                     61:  *
                     62:  * But latching the status is a command which the 8283 does not
                     63:  * recognize; the subsequent load is interpreted as one of
                     64:  * a pair to read the counter instead of the status.  (We get a
                     65:  * garbage bit instead of the one we expected, but that's no worse
                     66:  * than constant 0.)  But the 8283 doesn't like single reads.
                     67:  * (The 8284 is more forgiving.)
                     68:  *
                     69:  * So, to resolve all this, the following sequence is used:
                     70:  *
                     71:  * - Dummy read from counter 0 (low byte)
                     72:  * - Latch status and count (ignored by 8283)
                     73:  * - Read status (high byte on 8283)
                     74:  * - Latch count (ignored by 8284, as count is already latched)
                     75:  * - Read count (low)
                     76:  * - Read count (high)
                     77:  *
                     78:  * It would be better (a project for the future) to capture the counter
                     79:  * in a keyboard ISR, put it in a global variable, and have noise() read
                     80:  * the global.  This gets the most accurate possible time, and avoids
                     81:  * possible harmonic relationships with a keyboard polling loop.
                     82:  * (Which MS-DOS, silly thing that it is, almost certainly uses
                     83:  * internally.)
                     84:  */
                     85: static unsigned
                     86: pctimer0(void)
                     87: {
                     88:        unsigned count;
                     89: 
                     90:        inp(timer0);
                     91:        outp(timercntl, 0xC2);  /* Latch status and count for timer 0 */
                     92:        count = (inp(timer0) & 0x80) << 8;
                     93:        outp(timercntl, 0x00);  /* Latch count of timer 0 */
                     94:        count |= (inp(timer0) & 0xFF) >> 1;
                     95:        count |= (inp(timer0) & 0xFF) << 7;
                     96: 
                     97:        return count;
                     98: }
                     99: 
                    100: #endif /* MSDOS || __MSDOS__ */
                    101: 
                    102: 
                    103: #ifdef UNIX
                    104: 
                    105: #define NOISEDEBUG
                    106: #ifdef NOISEDEBUG
                    107: #include "pgp.h"       /* for verbose and pgpout */
                    108: #include <stdio.h>
                    109: #endif
                    110: 
                    111: /* Function needed for qsort() */
                    112: static int
                    113: noiseCompare(void const *p1, void const *p2)
                    114: {
                    115:         return *(int const *)p1 - *(int const *)p2;
                    116: }
                    117: 
                    118: 
                    119: #define DELTAS 15      /* Number of deltas to try */
                    120: 
                    121: /*
                    122:  * Find the resolution of the gettimeofday() clock by sampling
                    123:  * successive values until a tick boundary, at which point
                    124:  * the delta is entered into a table.  The median of the table is
                    125:  * returned as the system tick size.
                    126:  *
                    127:  * Some trickery is needed to defeat the habit systems have of
                    128:  * always incrementing the microseconds field so that no two calls
                    129:  * return the same value.  Thus, a "tick boundary" is assumed
                    130:  * when successive calls return a difference of >2 us.
                    131:  * (This catches cases where we make successive calls and one
                    132:  * other task sneaks in between.  More tasks in between are
                    133:  * sufficiently unlikely that they'll get cut off by the median
                    134:  * filter.
                    135:  *
                    136:  * When a tick boundary is found, the *first* time read during
                    137:  * the previous tick (tv_base) is subtracted from the new time
                    138:  * to get the microseconds per tick.
                    139:  *
                    140:  * The median of the ticks is taken to eliminate outliers due to
                    141:  * descheduling (extra large) or tv_base not being the "zero" time
                    142:  * in a given tick (slightly small).
                    143:  *
                    144:  * Note that Suns have a 1 us timer, and in SunOS 4.1, they return
                    145:  * that timer, but there is ~50 us of system-call overhead to get
                    146:  * it, so this overestimates the tick size consdierably.  On
                    147:  * SunOS 5.x/Solaris, the overhead has been cut to about 2.5 us,
                    148:  * so the inter-call time alternates between 2 and 3 us.  Some
                    149:  * better algorithms are required to cope with potentially faster
                    150:  * machines that really do return 1 us granularity.
                    151:  *
                    152:  * Current best idea (unimplemented): Sample a large number, and
                    153:  * track small (< 100 us) deltas in an array of counters, and
                    154:  * large ones in an array of deltas.  There should be three
                    155:  * bumps: 1 us auto-increment, the tick size (which may blend into
                    156:  * the previous bump), and time-slicing.  We want to throw out
                    157:  * the latter, then compute the average delta as the average cost
                    158:  * of making a call, then throw out the small values if they
                    159:  * are suspisciously smaller than this value.  Then some average
                    160:  * of the remainder should provide a good value for the cost of
                    161:  * making a call.
                    162:  *
                    163:  * The alternative to all this is to actually model the keystroke
                    164:  * latencies and compute the entropy directly.  A model considering
                    165:  * the previous interval only should be adequate.
                    166:  */
                    167: static unsigned
                    168: noiseTickSize(void)
                    169: {
                    170:         int i;
                    171:        int j;
                    172:         unsigned deltas[DELTAS];
                    173:         unsigned t;
                    174:         struct timeval tv_base, tv_old, tv_new;
                    175: 
                    176:         i = j = 0;
                    177:         gettimeofday(&tv_base, 0);
                    178:         tv_old = tv_base;
                    179:         do {
                    180:                 gettimeofday(&tv_new, 0);
                    181:                 if (tv_new.tv_usec > tv_old.tv_usec+2) {
                    182:                         deltas[i++] = tv_new.tv_usec - tv_base.tv_usec +
                    183:                                 1000000 * (tv_new.tv_sec - tv_base.tv_sec);
                    184:                         tv_base = tv_new;
                    185:                        j = 0;
                    186:                 }
                    187:                 tv_old = tv_new;
                    188: 
                    189:                /*
                    190:                 * If we are forever getting <= 2 us, then just assume
                    191:                 * it's 2 us.
                    192:                 */
                    193:                if (j++ > 10000)
                    194:                        return 2;
                    195:         } while (i < DELTAS);
                    196: 
                    197:         qsort(deltas, DELTAS, sizeof(deltas[0]), noiseCompare);
                    198: 
                    199:         t =  deltas[DELTAS/2];   /* Median */
                    200: 
                    201: #ifdef NOISEDEBUG
                    202:        if (verbose)
                    203:                fprintf(pgpout, "t = %u, clock frequency is %u Hz\n", t, (2000000+t)/(2*t));
                    204: #endif
                    205: 
                    206:        return t;
                    207: }
                    208: 
                    209: #endif /* UNIX */
                    210: 
                    211: 
                    212: /*
                    213:  * Add as much environmentally-derived random noise as possible
                    214:  * to the randPool.  Typically, this involves reading the most
                    215:  * accurate system clocks available.
                    216:  *
                    217:  * Returns the number of ticks that hasve passed since the last call,
                    218:  * for entropy estimation purposes.
                    219:  */
                    220: word32
                    221: noise(void)
                    222: {
                    223:        static word32 lastcounter;
                    224:        word32 delta;
                    225:        time_t tnow;
                    226:        clock_t cnow;
                    227: 
                    228:        cnow = clock();
                    229:        randPoolAddBytes((byte *)&cnow, sizeof(cnow));
                    230: 
                    231:        tnow = time((time_t *)0);
                    232:        randPoolAddBytes((byte *)&tnow, sizeof(tnow));
                    233: 
                    234: #if defined(MSDOS) || defined(__MSDOS__)
                    235:        {
                    236:                unsigned t;
                    237: 
                    238:                t = pctimer0();
                    239:                randPoolAddBytes((byte *)&t, sizeof(t));
                    240:                delta = t - (unsigned)lastcounter;
                    241:                lastcounter = t;
                    242:        }
                    243: #endif
                    244: 
                    245: #ifdef VMS
                    246:        {
                    247:                word32 t;
                    248:                /* VMS Hardware Clock */
                    249:                extern unsigned long vms_clock_bits[2];
                    250:                /* Clock update int. */
                    251:                extern const long vms_ticks_per_update;
                    252: 
                    253:                /* Capture fast system timer: */
                    254:                SYS$GETTIM(vms_clock_bits);
                    255:                randPoolAddBytes((byte *)&vms_clock_bits, sizeof(vms_clock_bits));
                    256:                t = vms_clock_bits[0] / vms_ticks_per_update;
                    257:                delta = t - lastcounter;
                    258:                lastcounter = t;
                    259:        }
                    260: #endif /* VMS */
                    261: 
                    262: #ifdef UNIX
                    263:        /* Get noise from gettimeofday() */
                    264:        {
                    265:                struct timeval tv;
                    266:                word32 t;
                    267:                static unsigned ticksize = 0;
                    268: 
                    269:                if (!ticksize)
                    270:                        ticksize = noiseTickSize();
                    271: 
                    272:                gettimeofday(&tv, NULL);
                    273:                randPoolAddBytes((byte *)&tv, sizeof(tv));
                    274: 
                    275:                /* This may wrap, but it's unsigned, so that's okay */
                    276:                t = tv.tv_sec * 1000000 + tv.tv_usec;
                    277:                delta = t-lastcounter;
                    278:                lastcounter = t;
                    279: 
                    280:                delta /= ticksize;
                    281:        }
                    282:        /* Get noise from times() */
                    283:        {
                    284:                clock_t t;
                    285:                struct tms tms;
                    286: 
                    287:                t = times(&tms);
                    288:                randPoolAddBytes((byte *)&tms, sizeof(tms));
                    289:                randPoolAddBytes((byte *)&t, sizeof(t));
                    290:        }
                    291: #endif /* UNIX */
                    292: 
                    293:        return delta;
                    294: }
                    295: 

unix.superglobalmegacorp.com

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