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

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>
        !            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.