|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.