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

  1. /*
  2.  * True random number computation and storage
  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. #include <stdlib.h>
  24. #include <string.h>
  25.  
  26. #include "randpool.h"
  27. #include "usuals.h"
  28. #include "md5.h"
  29. #ifdef MACTC5
  30. #include "TimeManager.h"
  31. #endif
  32.  
  33. /* The pool must be a multiple of the 16-byte (128-bit) MD5 block size */
  34. #define RANDPOOLWORDS ((RANDPOOLBITS+127 & ~127) >> 5)
  35. #if RANDPOOLWORDS <= 16
  36. /* #error is not portable, this has the same effect */
  37. #include "Random pool too small - please increase RANDPOOLBITS in randpool.h"
  38. #endif
  39.  
  40. /* Must be word-aligned, so make it words.  Cast to bytes as needed. */
  41. static word32 randPool[RANDPOOLWORDS];    /* Random pool */
  42. static unsigned randPoolGetPos = sizeof(randPool); /* Position to get from */
  43. static unsigned randPoolAddPos = 0;    /* Position to add to */
  44.  
  45. static void
  46. xorbytes(byte *dest, byte const *src, unsigned len)
  47. {
  48.     while (len--)
  49.         *dest++ ^= *src++;
  50. }
  51.  
  52. /*
  53.  * Destroys already-used random numbers.  Ensures no sensitive data
  54.  * remains in memory that can be recovered later.  This is also
  55.  * called to "stir in" newly acquired environmental noise bits before
  56.  * removing any random bytes.
  57.  *
  58.  * The transformation is carried out by "encrypting" the data in CFB
  59.  * mode with MD5 as the block cipher.  Then, to make certain the stirring
  60.  * operation is strictly one-way, we destroy the key, getting 64 bytes
  61.  * from the beginning of the pool and using them to reinitialize the
  62.  * key.  These bytes are not returned by randPoolGetBytes().
  63.  *
  64.  * The stirring operation is done twice, to ensure that each bit in the
  65.  * pool depends on each bit of entropy XORed in after each call to
  66.  * randPoolStir().
  67.  *
  68.  * To make this useful for pseudo-random (that is, repeatable) operations,
  69.  * the MD5 transformation is always done with a consistent byte order.
  70.  * MD5Transform itself works with 32-bit words, not bytes, so the pool,
  71.  * usually an array of bytes, is transformed into an array of 32-bit words,
  72.  * taking each group of 4 bytes in big-endian order.  At the end of the
  73.  * stirring, the transformation is reversed.
  74.  */
  75. void
  76. randPoolStir(void)
  77. {
  78.     int i;
  79.     byte *p;
  80.     word32 t;
  81.     word32 iv[4];
  82.     static word32 randPoolKey[16] = {0};
  83.  
  84.     /* Convert to word32s for stirring operation */
  85.     p = (byte *)randPool;
  86.     for (i = 0; i < RANDPOOLWORDS; i++) {
  87.         t = (word32)((unsigned)p[3]<<8 | p[2]) << 16 |
  88.                      (unsigned)p[1]<<8 | p[0];
  89.         randPool[i] = t;
  90.         p += 4;
  91.     }
  92.  
  93.     /* Start IV from last block of randPool */
  94.     memcpy(iv, randPool+RANDPOOLWORDS-4, sizeof(iv));
  95.  
  96.     /* First CFB pass */
  97.     for (i = 0; i < RANDPOOLWORDS; i += 4) {
  98.         MD5Transform(iv, randPoolKey);
  99.         iv[0] = randPool[i  ] ^= iv[0];
  100.         iv[1] = randPool[i+1] ^= iv[1];
  101.         iv[2] = randPool[i+2] ^= iv[2];
  102.         iv[3] = randPool[i+3] ^= iv[3];
  103.     }
  104.  
  105.     /* Get new key */
  106.     memcpy(randPoolKey, randPool, sizeof(randPoolKey));
  107.  
  108.     /* Second CFB pass */
  109.     for (i = 0; i < RANDPOOLWORDS; i += 4) {
  110.         MD5Transform(iv, randPoolKey);
  111.         iv[0] = randPool[i  ] ^= iv[0];
  112.         iv[1] = randPool[i+1] ^= iv[1];
  113.         iv[2] = randPool[i+2] ^= iv[2];
  114.         iv[3] = randPool[i+3] ^= iv[3];
  115.     }
  116.  
  117.     /* Get new key */
  118.     memcpy(randPoolKey, randPool, sizeof(randPoolKey));
  119.  
  120.     /* Wipe iv from memory */
  121.     memset(iv, 0, sizeof(iv));
  122.  
  123.     /* Convert randPool back to bytes for further use */
  124.     p = (byte *)randPool;
  125.     for (i = 0; i < RANDPOOLWORDS; i++) {
  126.         t = randPool[i];
  127.         p[0] = t>>24;
  128.         p[1] = t>>16;
  129.         p[2] = t>>8;
  130.         p[3] = t;
  131.         p += 4;
  132.     }
  133.  
  134.     /* Set up pointers for future addition or removal of random bytes */
  135.     randPoolAddPos = 0;
  136.     randPoolGetPos = sizeof(randPoolKey);
  137. #ifdef MACTC5
  138.     spinner();
  139. #endif
  140. }
  141.  
  142. /*
  143.  * Make a deposit of information (entropy) into the pool.  The bits
  144.  * deposited need not have any particular distribution; the stirring
  145.  * operation transformes them to uniformly-distributed bits.
  146.  */
  147. void
  148. randPoolAddBytes(byte const *buf, unsigned len)
  149. {
  150.     unsigned t;
  151.  
  152.     while (len > (t = sizeof(randPool) - randPoolAddPos)) {
  153.         xorbytes((byte *)randPool+randPoolAddPos, buf, t);
  154.         buf += t;
  155.         len -= t;
  156.         randPoolStir();
  157.     }
  158.  
  159.     if (len) {
  160.         xorbytes((byte *)randPool+randPoolAddPos, buf, len);
  161.         randPoolAddPos += len;
  162.         randPoolGetPos = sizeof(randPool); /* Force stir on get */
  163.     }
  164. }
  165.  
  166. /*
  167.  * Withdraw some bits from the pool.  Regardless of the distribution of the
  168.  * input bits, the bits returned are uniformly distributed, although they
  169.  * cannot, of course, contain more Shannon entropy than the input bits.
  170.  */
  171. void
  172. randPoolGetBytes(byte *buf, unsigned len)
  173. {
  174.     unsigned t;
  175.  
  176.     while (len > (t = sizeof(randPool) - randPoolGetPos)) {
  177.         memcpy(buf, (byte *)randPool+randPoolGetPos, t);
  178.         buf += t;
  179.         len -= t;
  180.         randPoolStir();
  181.     }
  182.  
  183. #ifdef MACTC5
  184.     spinner();
  185. #endif
  186.  
  187.     if (len) {
  188.         memcpy(buf, (byte *)randPool+randPoolGetPos, len);
  189.         randPoolGetPos += len;
  190.     }
  191. }
  192.  
  193. byte
  194. randPoolGetByte(void)
  195. {
  196.     if (randPoolGetPos == sizeof(randPool))
  197.         randPoolStir();
  198.  
  199. #ifdef MACTC5
  200.     spinner();
  201. #endif
  202.  
  203.     return (((byte *)randPool)[randPoolGetPos++]);
  204. }
  205.