home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1998 February / PCOnline_02_1998.iso / filesbbs / os2 / pgp263.arj / PGP263I.SRC / PGP263II.ZIP / src / noise.c < prev    next >
C/C++ Source or Header  |  1996-01-06  |  15KB  |  485 lines

  1. /*
  2.  * Get environmental noise.
  3.  *
  4.  * (c) Copyright 1990-1996 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. #endif /* UNIX */
  31.  
  32. #include <time.h>
  33. #include "usuals.h"
  34. #include "randpool.h"
  35. #include "noise.h"
  36. #ifdef MACTC5
  37. #include "TimeManager.h"
  38. #endif
  39.  
  40. #ifdef AMIGA  /* RKNOP 940613 */
  41. #include <devices/timer.h>
  42. #include <hardware/custom.h>
  43. #include <exec/execbase.h>
  44. extern __far struct Custom custom;   /* Custom chips */
  45. #include <proto/exec.h>
  46. #include <proto/timer.h>
  47.  
  48. /* Stuff used in noise.c, defined in random.c -- RKNOP 940613*/
  49. extern struct timerequest *TimerIO;
  50. extern union { struct timeval t;
  51.                struct EClockVal e;
  52.              } time0,time1;
  53. extern unsigned short use_eclock;
  54. #endif  /* AMIGA */
  55.  
  56. /* Some machines just don't have clock_t */
  57. #if defined(sun) && defined(i386)
  58. typedef long clock_t;
  59. #endif
  60.  
  61. #if defined(MSDOS) || defined(__MSDOS__)
  62.  
  63. /* Use IBM PC hardware timer (1.19 MHz) */
  64.  
  65. #ifdef __GO32__
  66. #include <pc.h>
  67. #else
  68. #include <conio.h>        /* for inp() and outp() */
  69. #include <dos.h>                /* same for Turbo C EWS */
  70. #endif
  71.  
  72. /* timer0 on 8253-5 on IBM PC or AT tics every .84 usec. */
  73. #define timer0        0x40    /* 8253 timer 0 port */
  74. #define timercntl    0x43    /* 8253 control register */
  75.  
  76. /*
  77.  * On an IBM PC, timer 0 ticks every .84 usec.  It counts down
  78.  * from 65536 by twos, toggling its output line after each
  79.  * step.  On an original IBM PC, we can thus only get 15 bits
  80.  * of the timer.  On a PC-AT or later, with an 8284 timer chip,
  81.  * we can get all 16 bits by reading the status, which has the
  82.  * state of the output bit in bit 7, and is effectively the
  83.  * high bit of the counter.
  84.  *
  85.  * But latching the status is a command which the 8283 does not
  86.  * recognize; the subsequent load is interpreted as one of
  87.  * a pair to read the counter instead of the status.  (We get a
  88.  * garbage bit instead of the one we expected, but that's no worse
  89.  * than constant 0.)  But the 8283 doesn't like single reads.
  90.  * (The 8284 is more forgiving.)
  91.  *
  92.  * So, to resolve all this, the following sequence is used:
  93.  *
  94.  * - Dummy read from counter 0 (low byte)
  95.  * - Latch status and count (ignored by 8283)
  96.  * - Read status (high byte on 8283)
  97.  * - Latch count (ignored by 8284, as count is already latched)
  98.  * - Read count (low)
  99.  * - Read count (high)
  100.  *
  101.  * It would be better (a project for the future) to capture the counter
  102.  * in a keyboard ISR, put it in a global variable, and have noise() read
  103.  * the global.  This gets the most accurate possible time, and avoids
  104.  * possible harmonic relationships with a keyboard polling loop.
  105.  * (Which MS-DOS, silly thing that it is, almost certainly uses
  106.  * internally.)
  107.  */
  108. static unsigned pctimer0(void)
  109. {
  110.     unsigned count;
  111.  
  112. #ifdef __GO32__
  113.     inportb(timer0);
  114.     outportb(timercntl, 0xC2);        /* Latch status and count for timer 0 */
  115.     count = (inportb(timer0) & 0x80) << 8;
  116.     outportb(timercntl, 0x00);        /* Latch count of timer 0 */
  117.     count |= (inportb(timer0) & 0xFF) >> 1;
  118.     count |= (inportb(timer0) & 0xFF) << 7;
  119. #else
  120.     inp(timer0);
  121.     outp(timercntl, 0xC2);    /* Latch status and count for timer 0 */
  122.     count = (inp(timer0) & 0x80) << 8;
  123.     outp(timercntl, 0x00);    /* Latch count of timer 0 */
  124.     count |= (inp(timer0) & 0xFF) >> 1;
  125.     count |= (inp(timer0) & 0xFF) << 7;
  126. #endif
  127.  
  128.     return count;
  129. }
  130.  
  131. #endif                /* MSDOS || __MSDOS__ */
  132.  
  133.  
  134. #ifdef UNIX
  135.  
  136. #define NOISEDEBUG
  137. #ifdef NOISEDEBUG
  138. #include "pgp.h"        /* for verbose and pgpout */
  139. #include <stdio.h>
  140. #endif
  141.  
  142. /* Function needed for qsort() */
  143. static int noiseCompare(void const *p1, void const *p2)
  144. {
  145.     return *(int const *) p1 - *(int const *) p2;
  146. }
  147.  
  148.  
  149. #define DELTAS 15        /* Number of deltas to try */
  150.  
  151. /*
  152.  * Find the resolution of the gettimeofday() clock by sampling
  153.  * successive values until a tick boundary, at which point
  154.  * the delta is entered into a table.  The median of the table is
  155.  * returned as the system tick size.
  156.  *
  157.  * Some trickery is needed to defeat the habit systems have of
  158.  * always incrementing the microseconds field so that no two calls
  159.  * return the same value.  Thus, a "tick boundary" is assumed
  160.  * when successive calls return a difference of >2 us.
  161.  * (This catches cases where we make successive calls and one
  162.  * other task sneaks in between.  More tasks in between are
  163.  * sufficiently unlikely that they'll get cut off by the median
  164.  * filter.
  165.  *
  166.  * When a tick boundary is found, the *first* time read during
  167.  * the previous tick (tv_base) is subtracted from the new time
  168.  * to get the microseconds per tick.
  169.  *
  170.  * The median of the ticks is taken to eliminate outliers due to
  171.  * descheduling (extra large) or tv_base not being the "zero" time
  172.  * in a given tick (slightly small).
  173.  *
  174.  * Note that Suns have a 1 us timer, and in SunOS 4.1, they return
  175.  * that timer, but there is ~50 us of system-call overhead to get
  176.  * it, so this overestimates the tick size consdierably.  On
  177.  * SunOS 5.x/Solaris, the overhead has been cut to about 2.5 us,
  178.  * so the inter-call time alternates between 2 and 3 us.  Some
  179.  * better algorithms are required to cope with potentially faster
  180.  * machines that really do return 1 us granularity.
  181.  *
  182.  * Current best idea (unimplemented): Sample a large number, and
  183.  * track small (< 100 us) deltas in an array of counters, and
  184.  * large ones in an array of deltas.  There should be three
  185.  * bumps: 1 us auto-increment, the tick size (which may blend into
  186.  * the previous bump), and time-slicing.  We want to throw out
  187.  * the latter, then compute the average delta as the average cost
  188.  * of making a call, then throw out the small values if they
  189.  * are suspisciously smaller than this value.  Then some average
  190.  * of the remainder should provide a good value for the cost of
  191.  * making a call.
  192.  *
  193.  * The alternative to all this is to actually model the keystroke
  194.  * latencies and compute the entropy directly.  A model considering
  195.  * the previous interval only should be adequate.
  196.  */
  197. static unsigned noiseTickSize(void)
  198. {
  199.     int i;
  200.     int j;
  201.     unsigned deltas[DELTAS];
  202.     unsigned t;
  203.     struct timeval tv_base, tv_old, tv_new;
  204.  
  205.     i = j = 0;
  206.     gettimeofday(&tv_base, 0);
  207.     tv_old = tv_base;
  208.     do {
  209.     gettimeofday(&tv_new, 0);
  210.     if (tv_new.tv_usec > tv_old.tv_usec + 2) {
  211.         deltas[i++] = tv_new.tv_usec - tv_base.tv_usec +
  212.         1000000 * (tv_new.tv_sec - tv_base.tv_sec);
  213.         tv_base = tv_new;
  214.         j = 0;
  215.     }
  216.     tv_old = tv_new;
  217.  
  218.     /*
  219.      * If we are forever getting <= 2 us, then just assume
  220.      * it's 2 us.
  221.      */
  222.     if (j++ > 10000)
  223.         return 2;
  224.     } while (i < DELTAS);
  225.  
  226.     qsort(deltas, DELTAS, sizeof(deltas[0]), noiseCompare);
  227.  
  228.     t = deltas[DELTAS / 2];    /* Median */
  229.  
  230. #ifdef NOISEDEBUG
  231.     if (verbose)
  232.     fprintf(pgpout, "t = %u, clock frequency is %u Hz\n",
  233.         t, (2000000 + t) / (2 * t));
  234. #endif
  235.  
  236.     return t;
  237. }
  238.  
  239. #endif                /* UNIX */
  240.  
  241.  
  242. /* (Written by Guy Geens 95/12/07)
  243. This routine gets the 200Hz counter from the system area.
  244. This part of memory is only accessible in supervisor mode.
  245. To add to randomness, also store 50/60/70Hz VBL (Vertical BLank)
  246. counter. (There are two flavours of this one: One counter is
  247. stopped while floppy disk access takes place, the other one keeps
  248. running. Which one to use? Both? No: the elapsed time would be
  249. connected (does this harm randomness? I don't know) and, when
  250. using a hard disk drive, the same!
  251. (I've just picked one.)
  252. */
  253.  
  254. #ifdef ATARI
  255. #ifdef __PUREC__
  256. #include <tos.h>
  257. #else
  258. #include <osbind.h>
  259. #endif
  260. static word32 counter,vblcount;
  261.  
  262. long getcount(void) {
  263.     counter= *((long*)0x4baL); /* _hz_200 */
  264.     vblcount= *((long*)0x466L); /* _frlock */
  265.     return counter;
  266. }
  267.  
  268. #endif
  269.  
  270.  
  271. /*
  272.  * Add as much environmentally-derived random noise as possible
  273.  * to the randPool.  Typically, this involves reading the most
  274.  * accurate system clocks available.
  275.  *
  276.  * Returns the number of ticks that has passed since the last call,
  277.  * for entropy estimation purposes.
  278.  */
  279. word32
  280. noise(void)
  281. {
  282.     static word32 lastcounter;
  283.     word32 delta;
  284.     time_t tnow;
  285.     clock_t cnow;
  286.  
  287.     cnow = clock();
  288.     randPoolAddBytes((byte *) & cnow, sizeof(cnow));
  289.  
  290.     tnow = time((time_t *) 0);
  291.     randPoolAddBytes((byte *) & tnow, sizeof(tnow));
  292.  
  293. #if defined(MSDOS) || defined(__MSDOS__)
  294.     {
  295.     unsigned t;
  296.  
  297.     t = pctimer0();
  298.     randPoolAddBytes((byte *) & t, sizeof(t));
  299.     delta = t - (unsigned) lastcounter;
  300.     lastcounter = t;
  301.     }
  302. #endif
  303.  
  304. #ifdef MACTC5
  305.     {
  306.         unsigned long t;
  307.         
  308.         delta = TMTicks();
  309.         t=lastcounter+=delta;
  310.         randPoolAddBytes((byte *)&t, sizeof(t));
  311.     }
  312. #endif
  313.  
  314. #ifdef WIN32
  315. /* Win32 provides QueryPerformanceCounter(), which does precisely what we need here */
  316.     {
  317.         /* What am I doing here ? : We can't #include <windows.h> to get the prototype
  318.            for QueryPerformanceCounter() because there are many namespace clashes
  319.            between PGP and windows.h. So, we hack in the prototype inline. When we get
  320.            a compiler which does namespaces, or someone removes all the clashes in PGP,
  321.            this will go.
  322.         */
  323. #if defined(_MSC_VER)  /* only valid if we're using the Microsoft compiler */
  324.     __declspec(dllimport) long __stdcall
  325.             QueryPerformanceCounter(__int64 *lpPerformanceCount);
  326.     unsigned t;
  327.     __int64 perf_count;
  328.  
  329.     QueryPerformanceCounter(&perf_count);
  330.     /* it doesn't matter if the return value is zero */
  331.     t = (unsigned) perf_count;
  332.     randPoolAddBytes((byte *) & t, sizeof(t));
  333.     delta = t - (unsigned) lastcounter;
  334.     lastcounter = t;
  335. #else  /* Not Microsoft compiler */
  336. #include "This compiler is not supported, modify the code above accordingly"
  337. #endif /* _MSC_VER */
  338.     }
  339. #endif /* WIN32 */
  340.  
  341. #ifdef VMS
  342.     {
  343.     word32 t;
  344.     /* VMS Hardware Clock */
  345.     extern unsigned long vms_clock_bits[2];
  346.     /* Clock update int. */
  347.     extern const long vms_ticks_per_update;
  348.  
  349.     /* Capture fast system timer: */
  350.     SYS$GETTIM(vms_clock_bits);
  351.     randPoolAddBytes((byte *) & vms_clock_bits, sizeof(vms_clock_bits));
  352.     t = vms_clock_bits[0] / vms_ticks_per_update;
  353.     delta = t - lastcounter;
  354.     lastcounter = t;
  355.     }
  356. #endif                /* VMS */
  357.  
  358. #ifdef UNIX
  359.     /* Get noise from gettimeofday() */
  360.     {
  361.     struct timeval tv;
  362.     word32 t;
  363.     static unsigned ticksize = 0;
  364.  
  365.     if (!ticksize)
  366.         ticksize = noiseTickSize();
  367.  
  368.     gettimeofday(&tv, NULL);
  369.     randPoolAddBytes((byte *) & tv, sizeof(tv));
  370.  
  371.     /* This may wrap, but it's unsigned, so that's okay */
  372.     t = tv.tv_sec * 1000000 + tv.tv_usec;
  373.     delta = t - lastcounter;
  374.     lastcounter = t;
  375.  
  376.     delta /= ticksize;
  377.     }
  378.     /* Get noise from times() */
  379.     {
  380.     clock_t t;
  381.     struct tms tms;
  382.  
  383.     t = times(&tms);
  384.     randPoolAddBytes((byte *) & tms, sizeof(tms));
  385.     randPoolAddBytes((byte *) & t, sizeof(t));
  386.     }
  387. #endif                /* UNIX */
  388.  
  389. #ifdef AMIGA     /* Whole next section added RKNOP 940613 */
  390. #define AMIGA_DELTAS 15
  391.  
  392.    {
  393.       static unsigned long ticksize = 0;
  394.       int i=0,j;
  395.       unsigned long deltas[AMIGA_DELTAS],swap;
  396.  
  397.  
  398.       /* NOTE -- this next section (reading the Eclock or the
  399.          microHz clock) will only happen within the do loop in
  400.          trueRandAccum()!! */
  401.  
  402.       if (TimerIO && TimerBase)
  403.       {  if (!ticksize)   /* Get tick size, similar to Unix */
  404.          {  Forbid();    /* Turn off multitasking to get ticksize */
  405.             if (use_eclock)
  406.               ReadEClock(&time0.e);
  407.             else
  408.               am_GetSysTime(&time0.t);
  409.             do
  410.             {   if (use_eclock)
  411.           {  ReadEClock(&time1.e);
  412.              if (time1.e.ev_lo>time0.e.ev_lo)
  413.                deltas[i++]=time1.e.ev_lo-time0.e.ev_lo;
  414.              time0.e.ev_lo=time1.e.ev_lo;
  415.              time0.e.ev_hi=time1.e.ev_hi;
  416.           }
  417.           else
  418.           {  am_GetSysTime(&time1.t);
  419.              if (CmpTime(&time0.t,&time1.t))
  420.                 deltas[i++]=1000000*(time1.t.tv_secs
  421.                       -time0.t.tv_secs)
  422.                   +(time1.t.tv_micro-time0.t.tv_micro);
  423.              time0.t.tv_secs=time1.t.tv_secs;
  424.              time0.t.tv_micro=time1.t.tv_micro;
  425.           }
  426.             } while (i<AMIGA_DELTAS);
  427.             for (i=0;i<AMIGA_DELTAS-1;i++)
  428.          for (j=i+1;j<AMIGA_DELTAS;j++)
  429.             if (deltas[j]<deltas[i])
  430.             {  swap=deltas[j];
  431.                deltas[j]=deltas[i];
  432.                deltas[i]=swap;
  433.             }
  434.             if ((ticksize=deltas[AMIGA_DELTAS/2])==0) ticksize=1;
  435.             Permit();
  436.          }
  437.  
  438.          if (use_eclock)
  439.          {  ReadEClock(&time1.e);
  440.             randPoolAddBytes((byte *)&time1.e.ev_lo,4);
  441.             delta=time1.e.ev_lo-time0.e.ev_lo;  /* wrap ok?, unsigned */
  442.             time0.e.ev_hi=time1.e.ev_hi;
  443.             time0.e.ev_lo=time1.e.ev_lo;
  444.          }
  445.          else
  446.          {  am_GetSysTime(&time1.t);
  447.             randPoolAddBytes((byte *)&time1.t,sizeof(time1.t));
  448.             delta=1000000*(time1.t.tv_secs - time0.t.tv_secs) +
  449.              time1.t.tv_micro - time0.t.tv_micro;
  450.             time0.t.tv_secs=time1.t.tv_secs;
  451.          time0.t.tv_micro=time1.t.tv_micro;
  452.          }
  453.          delta/=ticksize;
  454.       }
  455.  
  456.       /* Get some additional noise from the video beam poisition */
  457.       randPoolAddBytes((byte *)&custom.vhposr,2);
  458.  
  459.       /* Pull the ExecBase dispatch count */
  460.       randPoolAddBytes((byte *)
  461.              &((*(struct ExecBase **)4)->DispCount),4);
  462.    }
  463. #endif /* AMIGA (RKNOP 940613) */
  464.  
  465. #ifdef ATARI    /* Section written by Guy Geens <guy.geens@elis.rug.ac.be> 951207 */
  466.     Supexec(getcount);    /* Xbios 38 */
  467.     delta=counter-lastcounter;
  468.     lastcounter=counter;
  469.  
  470. #ifndef __PUREC__
  471.     randPoolAddBytes((byte*)&counter,4);
  472. #endif
  473.     /* Under Pure C, counter is the same as cnow (returned by clock()),
  474.     so it doesn't add to randomness.
  475.     I don't have any other C compiler, so I can't check whether they
  476.     also use the same counter. Please mail me further details */
  477.  
  478.      randPoolAddBytes((byte*)&vblcount,4);
  479.     /* Other compilers might require to comment this out and activate
  480.     the previous line. */
  481. #endif        /* End of section written by Guy Geens */
  482.  
  483.     return delta;
  484. }
  485.