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