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

1.1.1.2   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>
1.1.1.3 ! root       27: #include <sys/time.h>          /* For gettimeofday() */
        !            28: #include <sys/times.h>         /* for times() */
        !            29: #include <stdlib.h>            /* For qsort() */
1.1.1.2   root       30: 
1.1.1.3 ! root       31: #endif                         /* UNIX */
1.1.1.2   root       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: 
1.1.1.3 ! root       47: #include <conio.h>             /* for inp() and outp() */
1.1.1.2   root       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:  */
1.1.1.3 ! root       85: static unsigned pctimer0(void)
1.1.1.2   root       86: {
1.1.1.3 ! root       87:     unsigned count;
1.1.1.2   root       88: 
1.1.1.3 ! root       89:     inp(timer0);
        !            90:     outp(timercntl, 0xC2);     /* Latch status and count for timer 0 */
        !            91:     count = (inp(timer0) & 0x80) << 8;
        !            92:     outp(timercntl, 0x00);     /* Latch count of timer 0 */
        !            93:     count |= (inp(timer0) & 0xFF) >> 1;
        !            94:     count |= (inp(timer0) & 0xFF) << 7;
1.1.1.2   root       95: 
1.1.1.3 ! root       96:     return count;
1.1.1.2   root       97: }
                     98: 
1.1.1.3 ! root       99: #endif                         /* MSDOS || __MSDOS__ */
1.1.1.2   root      100: 
                    101: 
                    102: #ifdef UNIX
                    103: 
                    104: #define NOISEDEBUG
                    105: #ifdef NOISEDEBUG
1.1.1.3 ! root      106: #include "pgp.h"               /* for verbose and pgpout */
1.1.1.2   root      107: #include <stdio.h>
                    108: #endif
                    109: 
                    110: /* Function needed for qsort() */
1.1.1.3 ! root      111: static int noiseCompare(void const *p1, void const *p2)
1.1.1.2   root      112: {
1.1.1.3 ! root      113:     return *(int const *) p1 - *(int const *) p2;
1.1.1.2   root      114: }
                    115: 
                    116: 
1.1.1.3 ! root      117: #define DELTAS 15              /* Number of deltas to try */
1.1.1.2   root      118: 
                    119: /*
                    120:  * Find the resolution of the gettimeofday() clock by sampling
                    121:  * successive values until a tick boundary, at which point
                    122:  * the delta is entered into a table.  The median of the table is
                    123:  * returned as the system tick size.
                    124:  *
                    125:  * Some trickery is needed to defeat the habit systems have of
                    126:  * always incrementing the microseconds field so that no two calls
                    127:  * return the same value.  Thus, a "tick boundary" is assumed
                    128:  * when successive calls return a difference of >2 us.
                    129:  * (This catches cases where we make successive calls and one
                    130:  * other task sneaks in between.  More tasks in between are
                    131:  * sufficiently unlikely that they'll get cut off by the median
                    132:  * filter.
                    133:  *
                    134:  * When a tick boundary is found, the *first* time read during
                    135:  * the previous tick (tv_base) is subtracted from the new time
                    136:  * to get the microseconds per tick.
                    137:  *
                    138:  * The median of the ticks is taken to eliminate outliers due to
                    139:  * descheduling (extra large) or tv_base not being the "zero" time
                    140:  * in a given tick (slightly small).
                    141:  *
                    142:  * Note that Suns have a 1 us timer, and in SunOS 4.1, they return
                    143:  * that timer, but there is ~50 us of system-call overhead to get
                    144:  * it, so this overestimates the tick size consdierably.  On
                    145:  * SunOS 5.x/Solaris, the overhead has been cut to about 2.5 us,
                    146:  * so the inter-call time alternates between 2 and 3 us.  Some
                    147:  * better algorithms are required to cope with potentially faster
                    148:  * machines that really do return 1 us granularity.
                    149:  *
                    150:  * Current best idea (unimplemented): Sample a large number, and
                    151:  * track small (< 100 us) deltas in an array of counters, and
                    152:  * large ones in an array of deltas.  There should be three
                    153:  * bumps: 1 us auto-increment, the tick size (which may blend into
                    154:  * the previous bump), and time-slicing.  We want to throw out
                    155:  * the latter, then compute the average delta as the average cost
                    156:  * of making a call, then throw out the small values if they
                    157:  * are suspisciously smaller than this value.  Then some average
                    158:  * of the remainder should provide a good value for the cost of
                    159:  * making a call.
                    160:  *
                    161:  * The alternative to all this is to actually model the keystroke
                    162:  * latencies and compute the entropy directly.  A model considering
                    163:  * the previous interval only should be adequate.
                    164:  */
1.1.1.3 ! root      165: static unsigned noiseTickSize(void)
1.1.1.2   root      166: {
1.1.1.3 ! root      167:     int i;
        !           168:     int j;
        !           169:     unsigned deltas[DELTAS];
        !           170:     unsigned t;
        !           171:     struct timeval tv_base, tv_old, tv_new;
        !           172: 
        !           173:     i = j = 0;
        !           174:     gettimeofday(&tv_base, 0);
        !           175:     tv_old = tv_base;
        !           176:     do {
        !           177:        gettimeofday(&tv_new, 0);
        !           178:        if (tv_new.tv_usec > tv_old.tv_usec + 2) {
        !           179:            deltas[i++] = tv_new.tv_usec - tv_base.tv_usec +
        !           180:                1000000 * (tv_new.tv_sec - tv_base.tv_sec);
        !           181:            tv_base = tv_new;
        !           182:            j = 0;
        !           183:        }
        !           184:        tv_old = tv_new;
        !           185: 
        !           186:        /*
        !           187:         * If we are forever getting <= 2 us, then just assume
        !           188:         * it's 2 us.
        !           189:         */
        !           190:        if (j++ > 10000)
        !           191:            return 2;
        !           192:     } while (i < DELTAS);
1.1.1.2   root      193: 
1.1.1.3 ! root      194:     qsort(deltas, DELTAS, sizeof(deltas[0]), noiseCompare);
1.1.1.2   root      195: 
1.1.1.3 ! root      196:     t = deltas[DELTAS / 2];    /* Median */
1.1.1.2   root      197: 
                    198: #ifdef NOISEDEBUG
1.1.1.3 ! root      199:     if (verbose)
        !           200:        fprintf(pgpout, "t = %u, clock frequency is %u Hz\n",
        !           201:                t, (2000000 + t) / (2 * t));
1.1.1.2   root      202: #endif
                    203: 
1.1.1.3 ! root      204:     return t;
1.1.1.2   root      205: }
                    206: 
1.1.1.3 ! root      207: #endif                         /* UNIX */
1.1.1.2   root      208: 
                    209: 
                    210: /*
                    211:  * Add as much environmentally-derived random noise as possible
                    212:  * to the randPool.  Typically, this involves reading the most
                    213:  * accurate system clocks available.
                    214:  *
                    215:  * Returns the number of ticks that hasve passed since the last call,
                    216:  * for entropy estimation purposes.
                    217:  */
                    218: word32
                    219: noise(void)
                    220: {
1.1.1.3 ! root      221:     static word32 lastcounter;
        !           222:     word32 delta;
        !           223:     time_t tnow;
        !           224:     clock_t cnow;
1.1.1.2   root      225: 
1.1.1.3 ! root      226:     cnow = clock();
        !           227:     randPoolAddBytes((byte *) & cnow, sizeof(cnow));
1.1.1.2   root      228: 
1.1.1.3 ! root      229:     tnow = time((time_t *) 0);
        !           230:     randPoolAddBytes((byte *) & tnow, sizeof(tnow));
1.1.1.2   root      231: 
                    232: #if defined(MSDOS) || defined(__MSDOS__)
1.1.1.3 ! root      233:     {
        !           234:        unsigned t;
1.1.1.2   root      235: 
1.1.1.3 ! root      236:        t = pctimer0();
        !           237:        randPoolAddBytes((byte *) & t, sizeof(t));
        !           238:        delta = t - (unsigned) lastcounter;
        !           239:        lastcounter = t;
        !           240:     }
1.1.1.2   root      241: #endif
                    242: 
                    243: #ifdef VMS
1.1.1.3 ! root      244:     {
        !           245:        word32 t;
        !           246:        /* VMS Hardware Clock */
        !           247:        extern unsigned long vms_clock_bits[2];
        !           248:        /* Clock update int. */
        !           249:        extern const long vms_ticks_per_update;
        !           250: 
        !           251:        /* Capture fast system timer: */
        !           252:        SYS$GETTIM(vms_clock_bits);
        !           253:        randPoolAddBytes((byte *) & vms_clock_bits, sizeof(vms_clock_bits));
        !           254:        t = vms_clock_bits[0] / vms_ticks_per_update;
        !           255:        delta = t - lastcounter;
        !           256:        lastcounter = t;
        !           257:     }
        !           258: #endif                         /* VMS */
1.1.1.2   root      259: 
                    260: #ifdef UNIX
1.1.1.3 ! root      261:     /* Get noise from gettimeofday() */
        !           262:     {
        !           263:        struct timeval tv;
        !           264:        word32 t;
        !           265:        static unsigned ticksize = 0;
        !           266: 
        !           267:        if (!ticksize)
        !           268:            ticksize = noiseTickSize();
        !           269: 
        !           270:        gettimeofday(&tv, NULL);
        !           271:        randPoolAddBytes((byte *) & tv, sizeof(tv));
        !           272: 
        !           273:        /* This may wrap, but it's unsigned, so that's okay */
        !           274:        t = tv.tv_sec * 1000000 + tv.tv_usec;
        !           275:        delta = t - lastcounter;
        !           276:        lastcounter = t;
        !           277: 
        !           278:        delta /= ticksize;
        !           279:     }
        !           280:     /* Get noise from times() */
        !           281:     {
        !           282:        clock_t t;
        !           283:        struct tms tms;
        !           284: 
        !           285:        t = times(&tms);
        !           286:        randPoolAddBytes((byte *) & tms, sizeof(tms));
        !           287:        randPoolAddBytes((byte *) & t, sizeof(t));
        !           288:     }
        !           289: #endif                         /* UNIX */
1.1.1.2   root      290: 
1.1.1.3 ! root      291:     return delta;
1.1.1.2   root      292: }

unix.superglobalmegacorp.com

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