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