--- pgp/src/noise.c 2018/04/24 16:41:02 1.1.1.1 +++ pgp/src/noise.c 2018/04/24 16:42:18 1.1.1.2 @@ -1,295 +1,295 @@ -/* - * Get environmental noise. - * - * (c) Copyright 1990-1994 by Philip Zimmermann. All rights reserved. - * The author assumes no liability for damages resulting from the use - * of this software, even if the damage results from defects in this - * software. No warranty is expressed or implied. - * - * Note that while most PGP source modules bear Philip Zimmermann's - * copyright notice, many of them have been revised or entirely written - * by contributors who frequently failed to put their names in their - * code. Code that has been incorporated into PGP from other authors - * was either originally published in the public domain or is used with - * permission from the various authors. - * - * PGP is available for free to the public under certain restrictions. - * See the PGP User's Guide (included in the release package) for - * important information about licensing, patent restrictions on - * certain algorithms, trademarks, copyrights, and export controls. - * - * Written by Colin Plumb. - */ - - -#ifdef UNIX -#include -#include /* For gettimeofday() */ -#include /* for times() */ -#include /* For qsort() */ - -#endif /* UNIX */ - -#include -#include "usuals.h" -#include "randpool.h" -#include "noise.h" - -/* Some machines just don't have clock_t */ -#if defined(sun) && defined(i386) -typedef long clock_t; -#endif - -#if defined(MSDOS) || defined(__MSDOS__) - -/* Use IBM PC hardware timer (1.19 MHz) */ - -#include /* for inp() and outp() */ - -/* timer0 on 8253-5 on IBM PC or AT tics every .84 usec. */ -#define timer0 0x40 /* 8253 timer 0 port */ -#define timercntl 0x43 /* 8253 control register */ - -/* - * On an IBM PC, timer 0 ticks every .84 usec. It counts down - * from 65536 by twos, toggling its output line after each - * step. On an original IBM PC, we can thus only get 15 bits - * of the timer. On a PC-AT or later, with an 8284 timer chip, - * we can get all 16 bits by reading the status, which has the - * state of the output bit in bit 7, and is effectively the - * high bit of the counter. - * - * But latching the status is a command which the 8283 does not - * recognize; the subsequent load is interpreted as one of - * a pair to read the counter instead of the status. (We get a - * garbage bit instead of the one we expected, but that's no worse - * than constant 0.) But the 8283 doesn't like single reads. - * (The 8284 is more forgiving.) - * - * So, to resolve all this, the following sequence is used: - * - * - Dummy read from counter 0 (low byte) - * - Latch status and count (ignored by 8283) - * - Read status (high byte on 8283) - * - Latch count (ignored by 8284, as count is already latched) - * - Read count (low) - * - Read count (high) - * - * It would be better (a project for the future) to capture the counter - * in a keyboard ISR, put it in a global variable, and have noise() read - * the global. This gets the most accurate possible time, and avoids - * possible harmonic relationships with a keyboard polling loop. - * (Which MS-DOS, silly thing that it is, almost certainly uses - * internally.) - */ -static unsigned -pctimer0(void) -{ - unsigned count; - - inp(timer0); - outp(timercntl, 0xC2); /* Latch status and count for timer 0 */ - count = (inp(timer0) & 0x80) << 8; - outp(timercntl, 0x00); /* Latch count of timer 0 */ - count |= (inp(timer0) & 0xFF) >> 1; - count |= (inp(timer0) & 0xFF) << 7; - - return count; -} - -#endif /* MSDOS || __MSDOS__ */ - - -#ifdef UNIX - -#define NOISEDEBUG -#ifdef NOISEDEBUG -#include "pgp.h" /* for verbose and pgpout */ -#include -#endif - -/* Function needed for qsort() */ -static int -noiseCompare(void const *p1, void const *p2) -{ - return *(int const *)p1 - *(int const *)p2; -} - - -#define DELTAS 15 /* Number of deltas to try */ - -/* - * Find the resolution of the gettimeofday() clock by sampling - * successive values until a tick boundary, at which point - * the delta is entered into a table. The median of the table is - * returned as the system tick size. - * - * Some trickery is needed to defeat the habit systems have of - * always incrementing the microseconds field so that no two calls - * return the same value. Thus, a "tick boundary" is assumed - * when successive calls return a difference of >2 us. - * (This catches cases where we make successive calls and one - * other task sneaks in between. More tasks in between are - * sufficiently unlikely that they'll get cut off by the median - * filter. - * - * When a tick boundary is found, the *first* time read during - * the previous tick (tv_base) is subtracted from the new time - * to get the microseconds per tick. - * - * The median of the ticks is taken to eliminate outliers due to - * descheduling (extra large) or tv_base not being the "zero" time - * in a given tick (slightly small). - * - * Note that Suns have a 1 us timer, and in SunOS 4.1, they return - * that timer, but there is ~50 us of system-call overhead to get - * it, so this overestimates the tick size consdierably. On - * SunOS 5.x/Solaris, the overhead has been cut to about 2.5 us, - * so the inter-call time alternates between 2 and 3 us. Some - * better algorithms are required to cope with potentially faster - * machines that really do return 1 us granularity. - * - * Current best idea (unimplemented): Sample a large number, and - * track small (< 100 us) deltas in an array of counters, and - * large ones in an array of deltas. There should be three - * bumps: 1 us auto-increment, the tick size (which may blend into - * the previous bump), and time-slicing. We want to throw out - * the latter, then compute the average delta as the average cost - * of making a call, then throw out the small values if they - * are suspisciously smaller than this value. Then some average - * of the remainder should provide a good value for the cost of - * making a call. - * - * The alternative to all this is to actually model the keystroke - * latencies and compute the entropy directly. A model considering - * the previous interval only should be adequate. - */ -static unsigned -noiseTickSize(void) -{ - int i; - int j; - unsigned deltas[DELTAS]; - unsigned t; - struct timeval tv_base, tv_old, tv_new; - - i = j = 0; - gettimeofday(&tv_base, 0); - tv_old = tv_base; - do { - gettimeofday(&tv_new, 0); - if (tv_new.tv_usec > tv_old.tv_usec+2) { - deltas[i++] = tv_new.tv_usec - tv_base.tv_usec + - 1000000 * (tv_new.tv_sec - tv_base.tv_sec); - tv_base = tv_new; - j = 0; - } - tv_old = tv_new; - - /* - * If we are forever getting <= 2 us, then just assume - * it's 2 us. - */ - if (j++ > 10000) - return 2; - } while (i < DELTAS); - - qsort(deltas, DELTAS, sizeof(deltas[0]), noiseCompare); - - t = deltas[DELTAS/2]; /* Median */ - -#ifdef NOISEDEBUG - if (verbose) - fprintf(pgpout, "t = %u, clock frequency is %u Hz\n", t, (2000000+t)/(2*t)); -#endif - - return t; -} - -#endif /* UNIX */ - - -/* - * Add as much environmentally-derived random noise as possible - * to the randPool. Typically, this involves reading the most - * accurate system clocks available. - * - * Returns the number of ticks that hasve passed since the last call, - * for entropy estimation purposes. - */ -word32 -noise(void) -{ - static word32 lastcounter; - word32 delta; - time_t tnow; - clock_t cnow; - - cnow = clock(); - randPoolAddBytes((byte *)&cnow, sizeof(cnow)); - - tnow = time((time_t *)0); - randPoolAddBytes((byte *)&tnow, sizeof(tnow)); - -#if defined(MSDOS) || defined(__MSDOS__) - { - unsigned t; - - t = pctimer0(); - randPoolAddBytes((byte *)&t, sizeof(t)); - delta = t - (unsigned)lastcounter; - lastcounter = t; - } -#endif - -#ifdef VMS - { - word32 t; - /* VMS Hardware Clock */ - extern unsigned long vms_clock_bits[2]; - /* Clock update int. */ - extern const long vms_ticks_per_update; - - /* Capture fast system timer: */ - SYS$GETTIM(vms_clock_bits); - randPoolAddBytes((byte *)&vms_clock_bits, sizeof(vms_clock_bits)); - t = vms_clock_bits[0] / vms_ticks_per_update; - delta = t - lastcounter; - lastcounter = t; - } -#endif /* VMS */ - -#ifdef UNIX - /* Get noise from gettimeofday() */ - { - struct timeval tv; - word32 t; - static unsigned ticksize = 0; - - if (!ticksize) - ticksize = noiseTickSize(); - - gettimeofday(&tv, NULL); - randPoolAddBytes((byte *)&tv, sizeof(tv)); - - /* This may wrap, but it's unsigned, so that's okay */ - t = tv.tv_sec * 1000000 + tv.tv_usec; - delta = t-lastcounter; - lastcounter = t; - - delta /= ticksize; - } - /* Get noise from times() */ - { - clock_t t; - struct tms tms; - - t = times(&tms); - randPoolAddBytes((byte *)&tms, sizeof(tms)); - randPoolAddBytes((byte *)&t, sizeof(t)); - } -#endif /* UNIX */ - - return delta; -} - +/* + * Get environmental noise. + * + * (c) Copyright 1990-1994 by Philip Zimmermann. All rights reserved. + * The author assumes no liability for damages resulting from the use + * of this software, even if the damage results from defects in this + * software. No warranty is expressed or implied. + * + * Note that while most PGP source modules bear Philip Zimmermann's + * copyright notice, many of them have been revised or entirely written + * by contributors who frequently failed to put their names in their + * code. Code that has been incorporated into PGP from other authors + * was either originally published in the public domain or is used with + * permission from the various authors. + * + * PGP is available for free to the public under certain restrictions. + * See the PGP User's Guide (included in the release package) for + * important information about licensing, patent restrictions on + * certain algorithms, trademarks, copyrights, and export controls. + * + * Written by Colin Plumb. + */ + + +#ifdef UNIX +#include +#include /* For gettimeofday() */ +#include /* for times() */ +#include /* For qsort() */ + +#endif /* UNIX */ + +#include +#include "usuals.h" +#include "randpool.h" +#include "noise.h" + +/* Some machines just don't have clock_t */ +#if defined(sun) && defined(i386) +typedef long clock_t; +#endif + +#if defined(MSDOS) || defined(__MSDOS__) + +/* Use IBM PC hardware timer (1.19 MHz) */ + +#include /* for inp() and outp() */ + +/* timer0 on 8253-5 on IBM PC or AT tics every .84 usec. */ +#define timer0 0x40 /* 8253 timer 0 port */ +#define timercntl 0x43 /* 8253 control register */ + +/* + * On an IBM PC, timer 0 ticks every .84 usec. It counts down + * from 65536 by twos, toggling its output line after each + * step. On an original IBM PC, we can thus only get 15 bits + * of the timer. On a PC-AT or later, with an 8284 timer chip, + * we can get all 16 bits by reading the status, which has the + * state of the output bit in bit 7, and is effectively the + * high bit of the counter. + * + * But latching the status is a command which the 8283 does not + * recognize; the subsequent load is interpreted as one of + * a pair to read the counter instead of the status. (We get a + * garbage bit instead of the one we expected, but that's no worse + * than constant 0.) But the 8283 doesn't like single reads. + * (The 8284 is more forgiving.) + * + * So, to resolve all this, the following sequence is used: + * + * - Dummy read from counter 0 (low byte) + * - Latch status and count (ignored by 8283) + * - Read status (high byte on 8283) + * - Latch count (ignored by 8284, as count is already latched) + * - Read count (low) + * - Read count (high) + * + * It would be better (a project for the future) to capture the counter + * in a keyboard ISR, put it in a global variable, and have noise() read + * the global. This gets the most accurate possible time, and avoids + * possible harmonic relationships with a keyboard polling loop. + * (Which MS-DOS, silly thing that it is, almost certainly uses + * internally.) + */ +static unsigned +pctimer0(void) +{ + unsigned count; + + inp(timer0); + outp(timercntl, 0xC2); /* Latch status and count for timer 0 */ + count = (inp(timer0) & 0x80) << 8; + outp(timercntl, 0x00); /* Latch count of timer 0 */ + count |= (inp(timer0) & 0xFF) >> 1; + count |= (inp(timer0) & 0xFF) << 7; + + return count; +} + +#endif /* MSDOS || __MSDOS__ */ + + +#ifdef UNIX + +#define NOISEDEBUG +#ifdef NOISEDEBUG +#include "pgp.h" /* for verbose and pgpout */ +#include +#endif + +/* Function needed for qsort() */ +static int +noiseCompare(void const *p1, void const *p2) +{ + return *(int const *)p1 - *(int const *)p2; +} + + +#define DELTAS 15 /* Number of deltas to try */ + +/* + * Find the resolution of the gettimeofday() clock by sampling + * successive values until a tick boundary, at which point + * the delta is entered into a table. The median of the table is + * returned as the system tick size. + * + * Some trickery is needed to defeat the habit systems have of + * always incrementing the microseconds field so that no two calls + * return the same value. Thus, a "tick boundary" is assumed + * when successive calls return a difference of >2 us. + * (This catches cases where we make successive calls and one + * other task sneaks in between. More tasks in between are + * sufficiently unlikely that they'll get cut off by the median + * filter. + * + * When a tick boundary is found, the *first* time read during + * the previous tick (tv_base) is subtracted from the new time + * to get the microseconds per tick. + * + * The median of the ticks is taken to eliminate outliers due to + * descheduling (extra large) or tv_base not being the "zero" time + * in a given tick (slightly small). + * + * Note that Suns have a 1 us timer, and in SunOS 4.1, they return + * that timer, but there is ~50 us of system-call overhead to get + * it, so this overestimates the tick size consdierably. On + * SunOS 5.x/Solaris, the overhead has been cut to about 2.5 us, + * so the inter-call time alternates between 2 and 3 us. Some + * better algorithms are required to cope with potentially faster + * machines that really do return 1 us granularity. + * + * Current best idea (unimplemented): Sample a large number, and + * track small (< 100 us) deltas in an array of counters, and + * large ones in an array of deltas. There should be three + * bumps: 1 us auto-increment, the tick size (which may blend into + * the previous bump), and time-slicing. We want to throw out + * the latter, then compute the average delta as the average cost + * of making a call, then throw out the small values if they + * are suspisciously smaller than this value. Then some average + * of the remainder should provide a good value for the cost of + * making a call. + * + * The alternative to all this is to actually model the keystroke + * latencies and compute the entropy directly. A model considering + * the previous interval only should be adequate. + */ +static unsigned +noiseTickSize(void) +{ + int i; + int j; + unsigned deltas[DELTAS]; + unsigned t; + struct timeval tv_base, tv_old, tv_new; + + i = j = 0; + gettimeofday(&tv_base, 0); + tv_old = tv_base; + do { + gettimeofday(&tv_new, 0); + if (tv_new.tv_usec > tv_old.tv_usec+2) { + deltas[i++] = tv_new.tv_usec - tv_base.tv_usec + + 1000000 * (tv_new.tv_sec - tv_base.tv_sec); + tv_base = tv_new; + j = 0; + } + tv_old = tv_new; + + /* + * If we are forever getting <= 2 us, then just assume + * it's 2 us. + */ + if (j++ > 10000) + return 2; + } while (i < DELTAS); + + qsort(deltas, DELTAS, sizeof(deltas[0]), noiseCompare); + + t = deltas[DELTAS/2]; /* Median */ + +#ifdef NOISEDEBUG + if (verbose) + fprintf(pgpout, "t = %u, clock frequency is %u Hz\n", t, (2000000+t)/(2*t)); +#endif + + return t; +} + +#endif /* UNIX */ + + +/* + * Add as much environmentally-derived random noise as possible + * to the randPool. Typically, this involves reading the most + * accurate system clocks available. + * + * Returns the number of ticks that hasve passed since the last call, + * for entropy estimation purposes. + */ +word32 +noise(void) +{ + static word32 lastcounter; + word32 delta; + time_t tnow; + clock_t cnow; + + cnow = clock(); + randPoolAddBytes((byte *)&cnow, sizeof(cnow)); + + tnow = time((time_t *)0); + randPoolAddBytes((byte *)&tnow, sizeof(tnow)); + +#if defined(MSDOS) || defined(__MSDOS__) + { + unsigned t; + + t = pctimer0(); + randPoolAddBytes((byte *)&t, sizeof(t)); + delta = t - (unsigned)lastcounter; + lastcounter = t; + } +#endif + +#ifdef VMS + { + word32 t; + /* VMS Hardware Clock */ + extern unsigned long vms_clock_bits[2]; + /* Clock update int. */ + extern const long vms_ticks_per_update; + + /* Capture fast system timer: */ + SYS$GETTIM(vms_clock_bits); + randPoolAddBytes((byte *)&vms_clock_bits, sizeof(vms_clock_bits)); + t = vms_clock_bits[0] / vms_ticks_per_update; + delta = t - lastcounter; + lastcounter = t; + } +#endif /* VMS */ + +#ifdef UNIX + /* Get noise from gettimeofday() */ + { + struct timeval tv; + word32 t; + static unsigned ticksize = 0; + + if (!ticksize) + ticksize = noiseTickSize(); + + gettimeofday(&tv, NULL); + randPoolAddBytes((byte *)&tv, sizeof(tv)); + + /* This may wrap, but it's unsigned, so that's okay */ + t = tv.tv_sec * 1000000 + tv.tv_usec; + delta = t-lastcounter; + lastcounter = t; + + delta /= ticksize; + } + /* Get noise from times() */ + { + clock_t t; + struct tms tms; + + t = times(&tms); + randPoolAddBytes((byte *)&tms, sizeof(tms)); + randPoolAddBytes((byte *)&t, sizeof(t)); + } +#endif /* UNIX */ + + return delta; +} +