home *** CD-ROM | disk | FTP | other *** search
/ RISC DISC 2 / RISC_DISC_2.iso / pd_share / utilities / cli / pgp2 / src / c / noise < prev    next >
Encoding:
Text File  |  1995-06-06  |  12.6 KB  |  421 lines

  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. #ifdef AMIGA  /* RKNOP 940613 */
  39. #include <devices/timer.h>
  40. #include <hardware/custom.h>
  41. #include <exec/execbase.h>
  42. extern __far struct Custom custom;   /* Custom chips */
  43. #include <proto/exec.h>
  44. #include <proto/timer.h>
  45.  
  46. /* Stuff used in noise.c, defined in random.c -- RKNOP 940613*/
  47. extern struct timerequest *TimerIO;
  48. extern union { struct timeval t;
  49.                struct EClockVal e;
  50.              } time0,time1;
  51. extern unsigned short use_eclock;
  52. #endif  /* AMIGA */
  53.  
  54. /* Some machines just don't have clock_t */
  55. #if defined(sun) && defined(i386)
  56. typedef long clock_t;
  57. #endif
  58.  
  59. #if defined(MSDOS) || defined(__MSDOS__)
  60.  
  61. /* Use IBM PC hardware timer (1.19 MHz) */
  62.  
  63. #include <conio.h>        /* for inp() and outp() */
  64. #include <dos.h>                /* same for Turbo C EWS */
  65.  
  66. /* timer0 on 8253-5 on IBM PC or AT tics every .84 usec. */
  67. #define timer0        0x40    /* 8253 timer 0 port */
  68. #define timercntl    0x43    /* 8253 control register */
  69.  
  70. /*
  71.  * On an IBM PC, timer 0 ticks every .84 usec.  It counts down
  72.  * from 65536 by twos, toggling its output line after each
  73.  * step.  On an original IBM PC, we can thus only get 15 bits
  74.  * of the timer.  On a PC-AT or later, with an 8284 timer chip,
  75.  * we can get all 16 bits by reading the status, which has the
  76.  * state of the output bit in bit 7, and is effectively the
  77.  * high bit of the counter.
  78.  *
  79.  * But latching the status is a command which the 8283 does not
  80.  * recognize; the subsequent load is interpreted as one of
  81.  * a pair to read the counter instead of the status.  (We get a
  82.  * garbage bit instead of the one we expected, but that's no worse
  83.  * than constant 0.)  But the 8283 doesn't like single reads.
  84.  * (The 8284 is more forgiving.)
  85.  *
  86.  * So, to resolve all this, the following sequence is used:
  87.  *
  88.  * - Dummy read from counter 0 (low byte)
  89.  * - Latch status and count (ignored by 8283)
  90.  * - Read status (high byte on 8283)
  91.  * - Latch count (ignored by 8284, as count is already latched)
  92.  * - Read count (low)
  93.  * - Read count (high)
  94.  *
  95.  * It would be better (a project for the future) to capture the counter
  96.  * in a keyboard ISR, put it in a global variable, and have noise() read
  97.  * the global.  This gets the most accurate possible time, and avoids
  98.  * possible harmonic relationships with a keyboard polling loop.
  99.  * (Which MS-DOS, silly thing that it is, almost certainly uses
  100.  * internally.)
  101.  */
  102. static unsigned pctimer0(void)
  103. {
  104.     unsigned count;
  105.  
  106.     inp(timer0);
  107.     outp(timercntl, 0xC2);    /* Latch status and count for timer 0 */
  108.     count = (inp(timer0) & 0x80) << 8;
  109.     outp(timercntl, 0x00);    /* Latch count of timer 0 */
  110.     count |= (inp(timer0) & 0xFF) >> 1;
  111.     count |= (inp(timer0) & 0xFF) << 7;
  112.  
  113.     return count;
  114. }
  115.  
  116. #endif                /* MSDOS || __MSDOS__ */
  117.  
  118.  
  119. #ifdef UNIX
  120.  
  121. #define NOISEDEBUG
  122. #ifdef NOISEDEBUG
  123. #include "pgp.h"        /* for verbose and pgpout */
  124. #include <stdio.h>
  125. #endif
  126.  
  127. /* Function needed for qsort() */
  128. static int noiseCompare(void const *p1, void const *p2)
  129. {
  130.     return *(int const *) p1 - *(int const *) p2;
  131. }
  132.  
  133.  
  134. #define DELTAS 15        /* Number of deltas to try */
  135.  
  136. /*
  137.  * Find the resolution of the gettimeofday() clock by sampling
  138.  * successive values until a tick boundary, at which point
  139.  * the delta is entered into a table.  The median of the table is
  140.  * returned as the system tick size.
  141.  *
  142.  * Some trickery is needed to defeat the habit systems have of
  143.  * always incrementing the microseconds field so that no two calls
  144.  * return the same value.  Thus, a "tick boundary" is assumed
  145.  * when successive calls return a difference of >2 us.
  146.  * (This catches cases where we make successive calls and one
  147.  * other task sneaks in between.  More tasks in between are
  148.  * sufficiently unlikely that they'll get cut off by the median
  149.  * filter.
  150.  *
  151.  * When a tick boundary is found, the *first* time read during
  152.  * the previous tick (tv_base) is subtracted from the new time
  153.  * to get the microseconds per tick.
  154.  *
  155.  * The median of the ticks is taken to eliminate outliers due to
  156.  * descheduling (extra large) or tv_base not being the "zero" time
  157.  * in a given tick (slightly small).
  158.  *
  159.  * Note that Suns have a 1 us timer, and in SunOS 4.1, they return
  160.  * that timer, but there is ~50 us of system-call overhead to get
  161.  * it, so this overestimates the tick size consdierably.  On
  162.  * SunOS 5.x/Solaris, the overhead has been cut to about 2.5 us,
  163.  * so the inter-call time alternates between 2 and 3 us.  Some
  164.  * better algorithms are required to cope with potentially faster
  165.  * machines that really do return 1 us granularity.
  166.  *
  167.  * Current best idea (unimplemented): Sample a large number, and
  168.  * track small (< 100 us) deltas in an array of counters, and
  169.  * large ones in an array of deltas.  There should be three
  170.  * bumps: 1 us auto-increment, the tick size (which may blend into
  171.  * the previous bump), and time-slicing.  We want to throw out
  172.  * the latter, then compute the average delta as the average cost
  173.  * of making a call, then throw out the small values if they
  174.  * are suspisciously smaller than this value.  Then some average
  175.  * of the remainder should provide a good value for the cost of
  176.  * making a call.
  177.  *
  178.  * The alternative to all this is to actually model the keystroke
  179.  * latencies and compute the entropy directly.  A model considering
  180.  * the previous interval only should be adequate.
  181.  */
  182. static unsigned noiseTickSize(void)
  183. {
  184.     int i;
  185.     int j;
  186.     unsigned deltas[DELTAS];
  187.     unsigned t;
  188.     struct timeval tv_base, tv_old, tv_new;
  189.  
  190.     i = j = 0;
  191.     gettimeofday(&tv_base, 0);
  192.     tv_old = tv_base;
  193.     do {
  194.     gettimeofday(&tv_new, 0);
  195.     if (tv_new.tv_usec > tv_old.tv_usec + 2) {
  196.         deltas[i++] = tv_new.tv_usec - tv_base.tv_usec +
  197.         1000000 * (tv_new.tv_sec - tv_base.tv_sec);
  198.         tv_base = tv_new;
  199.         j = 0;
  200.     }
  201.     tv_old = tv_new;
  202.  
  203.     /*
  204.      * If we are forever getting <= 2 us, then just assume
  205.      * it's 2 us.
  206.      */
  207.     if (j++ > 10000)
  208.         return 2;
  209.     } while (i < DELTAS);
  210.  
  211.     qsort(deltas, DELTAS, sizeof(deltas[0]), noiseCompare);
  212.  
  213.     t = deltas[DELTAS / 2];    /* Median */
  214.  
  215. #ifdef NOISEDEBUG
  216.     if (verbose)
  217.     fprintf(pgpout, "t = %u, clock frequency is %u Hz\n",
  218.         t, (2000000 + t) / (2 * t));
  219. #endif
  220.  
  221.     return t;
  222. }
  223.  
  224. #endif                /* UNIX */
  225.  
  226.  
  227. /*
  228.  * Add as much environmentally-derived random noise as possible
  229.  * to the randPool.  Typically, this involves reading the most
  230.  * accurate system clocks available.
  231.  *
  232.  * Returns the number of ticks that hasve passed since the last call,
  233.  * for entropy estimation purposes.
  234.  */
  235. word32
  236. noise(void)
  237. {
  238.     static word32 lastcounter;
  239.     word32 delta;
  240.     time_t tnow;
  241.     clock_t cnow;
  242. #ifdef RISC_OS
  243. /* See below for why we want this -- GJM */
  244.     static int delta0=0;    /* min time for a call to |ioc_t1()| */
  245. #endif
  246.  
  247.     cnow = clock();
  248.     randPoolAddBytes((byte *) & cnow, sizeof(cnow));
  249.  
  250.     tnow = time((time_t *) 0);
  251.     randPoolAddBytes((byte *) & tnow, sizeof(tnow));
  252.  
  253. #ifdef RISC_OS
  254.     {
  255.       /* Read IOC timer 1 (IOMD timer 1 on Risc PC), which is
  256.        * a 16-bit counter *decrementing* at 2MHz.
  257.        * For |delta| we just return the change in this;
  258.        * this is slightly conservative but saves the trouble
  259.        * of trying to integrate the results with those of
  260.        * |clock()|.
  261.        * We also reduce |delta|: the call to |ioc_t1()| takes
  262.        * time, largely because we need to call a SWI. The first
  263.        * time |noise()| is called, we make a feeble attempt at
  264.        * calibration.  -- GJM
  265.        */
  266.     unsigned t=ioc_t1();
  267.         if (!delta0) {
  268.           int t0,t1,t2,t3;
  269.           t0=ioc_t1(); t1=ioc_t1(); t2=ioc_t1(); t3=ioc_t1();
  270.           t0=(t0-t1)&65535; t1=(t1-t2)&65535; t2=(t2-t3)&65535;
  271.           if (t1<t0) t0=t1;
  272.           if (t2<t0) t0=t2;
  273.           delta0 = t0 ? t0 : 1;    /* of course it won't be 0 really */
  274.         }
  275.     randPoolAddBytes((byte *)&t,2);
  276.     { delta=lastcounter-t;
  277.       if (((int)delta)<0) delta+=65536;
  278.       if (delta<delta0) delta=0; else delta-=delta0;
  279.     }
  280.     lastcounter=t;
  281.     }
  282. #endif
  283.  
  284. #if defined(MSDOS) || defined(__MSDOS__)
  285.     {
  286.     unsigned t;
  287.  
  288.     t = pctimer0();
  289.     randPoolAddBytes((byte *) & t, sizeof(t));
  290.     delta = t - (unsigned) lastcounter;
  291.     lastcounter = t;
  292.     }
  293. #endif
  294.  
  295. #ifdef VMS
  296.     {
  297.     word32 t;
  298.     /* VMS Hardware Clock */
  299.     extern unsigned long vms_clock_bits[2];
  300.     /* Clock update int. */
  301.     extern const long vms_ticks_per_update;
  302.  
  303.     /* Capture fast system timer: */
  304.     SYS$GETTIM(vms_clock_bits);
  305.     randPoolAddBytes((byte *) & vms_clock_bits, sizeof(vms_clock_bits));
  306.     t = vms_clock_bits[0] / vms_ticks_per_update;
  307.     delta = t - lastcounter;
  308.     lastcounter = t;
  309.     }
  310. #endif                /* VMS */
  311.  
  312. #ifdef UNIX
  313.     /* Get noise from gettimeofday() */
  314.     {
  315.     struct timeval tv;
  316.     word32 t;
  317.     static unsigned ticksize = 0;
  318.  
  319.     if (!ticksize)
  320.         ticksize = noiseTickSize();
  321.  
  322.     gettimeofday(&tv, NULL);
  323.     randPoolAddBytes((byte *) & tv, sizeof(tv));
  324.  
  325.     /* This may wrap, but it's unsigned, so that's okay */
  326.     t = tv.tv_sec * 1000000 + tv.tv_usec;
  327.     delta = t - lastcounter;
  328.     lastcounter = t;
  329.  
  330.     delta /= ticksize;
  331.     }
  332.     /* Get noise from times() */
  333.     {
  334.     clock_t t;
  335.     struct tms tms;
  336.  
  337.     t = times(&tms);
  338.     randPoolAddBytes((byte *) & tms, sizeof(tms));
  339.     randPoolAddBytes((byte *) & t, sizeof(t));
  340.     }
  341. #endif                /* UNIX */
  342.  
  343. #ifdef AMIGA     /* Whole next section added RKNOP 940613 */
  344. #define AMIGA_DELTAS 15
  345.  
  346.    {
  347.       static unsigned long ticksize = 0;
  348.       int i=0,j;
  349.       unsigned long deltas[AMIGA_DELTAS],swap;
  350.  
  351.  
  352.       /* NOTE -- this next section (reading the Eclock or the
  353.          microHz clock) will only happen within the do loop in
  354.          trueRandAccum()!! */
  355.  
  356.       if (TimerIO && TimerBase)
  357.       {  if (!ticksize)   /* Get tick size, similar to Unix */
  358.          {  Forbid();    /* Turn off multitasking to get ticksize */
  359.             if (use_eclock)
  360.          ReadEClock(&time0.e);
  361.             else
  362.          GetSysTime(&time0.t);
  363.             do
  364.             {   if (use_eclock)
  365.           {  ReadEClock(&time1.e);
  366.              if (time1.e.ev_lo>time0.e.ev_lo)
  367.                deltas[i++]=time1.e.ev_lo-time0.e.ev_lo;
  368.              time0.e.ev_lo=time1.e.ev_lo;
  369.              time0.e.ev_hi=time1.e.ev_hi;
  370.           }
  371.           else
  372.           {  GetSysTime(&time1.t);
  373.              if (CmpTime(&time0.t,&time1.t))
  374.                 deltas[i++]=1000000*(time1.t.tv_secs
  375.                       -time0.t.tv_secs)
  376.                   +(time1.t.tv_micro-time0.t.tv_micro);
  377.              time0.t.tv_secs=time1.t.tv_secs;
  378.              time0.t.tv_micro=time1.t.tv_micro;
  379.           }
  380.             } while (i<AMIGA_DELTAS);
  381.             for (i=0;i<AMIGA_DELTAS-1;i++)
  382.          for (j=i+1;j<AMIGA_DELTAS;j++)
  383.             if (deltas[j]<deltas[i])
  384.             {  swap=deltas[j];
  385.                deltas[j]=deltas[i];
  386.                deltas[i]=swap;
  387.             }
  388.             if ((ticksize=deltas[AMIGA_DELTAS/2])==0) ticksize=1;
  389.             Permit();
  390.          }
  391.  
  392.          if (use_eclock)
  393.          {  ReadEClock(&time1.e);
  394.             randPoolAddBytes((byte *)&time1.e.ev_lo,4);
  395.             delta=time1.e.ev_lo-time0.e.ev_lo;  /* wrap ok?, unsigned */
  396.             time0.e.ev_hi=time1.e.ev_hi;
  397.             time0.e.ev_lo=time1.e.ev_lo;
  398.          }
  399.          else
  400.          {  GetSysTime(&time1.t);
  401.             randPoolAddBytes((byte *)&time1.t,sizeof(time1.t));
  402.             delta=1000000*(time1.t.tv_secs - time0.t.tv_secs) +
  403.              time1.t.tv_micro - time0.t.tv_micro;
  404.             time0.t.tv_secs=time1.t.tv_secs;
  405.          time0.t.tv_micro=time1.t.tv_micro;
  406.          }
  407.          delta/=ticksize;
  408.       }
  409.  
  410.       /* Get some additional noise from the video beam poisition */
  411.       randPoolAddBytes((byte *)&custom.vhposr,2);
  412.  
  413.       /* Pull the ExecBase dispatch count */
  414.       randPoolAddBytes((byte *)
  415.              &((*(struct ExecBase **)4)->DispCount),4);
  416.    }
  417. #endif /* AMIGA (RKNOP 940613) */
  418.  
  419.     return delta;
  420. }
  421.