2
0

randpool.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /*
  2. * Copyright (c) 1993, 1994 Colin Plumb. All rights reserved.
  3. * For licensing and other legal details, see the file legal.c.
  4. *
  5. * True random number computation and storage
  6. *
  7. */
  8. #include "first.h"
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include "md5.h"
  12. #include "randpool.h"
  13. #include "usuals.h"
  14. /* This is a parameter of the MD5 algorithm */
  15. #define RANDKEYWORDS 16
  16. /* The pool must be a multiple of the 16-byte (128-bit) MD5 block size */
  17. #define RANDPOOLWORDS (((RANDPOOLBITS+127) & ~127) >> 5)
  18. #if RANDPOOLWORDS <= RANDKEYWORDS
  19. #error Random pool too small - please increase RANDPOOLBITS in randpool.h
  20. #endif
  21. /* Must be word-aligned, so make it words. Cast to bytes as needed. */
  22. static word32 randPool[RANDPOOLWORDS]; /* Random pool */
  23. static word32 randKey[RANDKEYWORDS]; /* Random pool */
  24. static unsigned randKeyAddPos = 0; /* Position to add to */
  25. static unsigned randPoolGetPos = 16; /* Position to get from */
  26. /*
  27. * Destroys already-used random numbers. Ensures no sensitive data
  28. * remains in memory that can be recovered later. This is also
  29. * called to "stir in" newly acquired environmental noise bits before
  30. * removing any random bytes.
  31. *
  32. * The transformation is carried out by "encrypting" the data in CFB
  33. * mode with MD5 as the block cipher. Then, to make certain the stirring
  34. * operation is strictly one-way, we destroy the key, getting 64 bytes
  35. * from the beginning of the pool and using them to reinitialize the
  36. * key. These bytes are not returned by randPoolGetBytes().
  37. *
  38. * The key for the stirring operation is the XOR of some bytes from the
  39. * previous pool contents (not provably necessary, but it produces uniformly
  40. * distributed keys, which "feels better") and the newly added raw noise,
  41. * which will have a profound effect on every bit in the pool.
  42. *
  43. * To make this useful for pseudo-random (that is, repeatable) operations,
  44. * the MD5 transformation is always done with a consistent byte order.
  45. * MD5Transform itself works with 32-bit words, not bytes, so the pool,
  46. * usually an array of bytes, is transformed into an array of 32-bit words,
  47. * taking each group of 4 bytes in big-endian order. At the end of the
  48. * stirring, the transformation is reversed.
  49. */
  50. void
  51. randPoolStir(void)
  52. {
  53. int i;
  54. word32 iv[4];
  55. /* Convert to word32s for stirring operation */
  56. byteSwap(randPool, RANDPOOLWORDS);
  57. byteSwap(randKey, RANDKEYWORDS);
  58. /* Start IV from last block of randPool */
  59. memcpy(iv, randPool+RANDPOOLWORDS-4, sizeof(iv));
  60. /* CFB pass */
  61. for (i = 0; i < RANDPOOLWORDS; i += 4) {
  62. MD5Transform(iv, randKey);
  63. iv[0] = randPool[i ] ^= iv[0];
  64. iv[1] = randPool[i+1] ^= iv[1];
  65. iv[2] = randPool[i+2] ^= iv[2];
  66. iv[3] = randPool[i+3] ^= iv[3];
  67. }
  68. /* Wipe iv from memory */
  69. iv[3] = iv[2] = iv[1] = iv[0] = 0;
  70. /* Convert randPool back to bytes for further use */
  71. byteSwap(randPool, RANDPOOLWORDS);
  72. /* Get new key */
  73. memcpy(randKey, randPool, sizeof(randKey));
  74. /* Set up pointers for future addition or removal of random bytes */
  75. randKeyAddPos = 0;
  76. randPoolGetPos = sizeof(randKey);
  77. }
  78. /*
  79. * Make a deposit of information (entropy) into the pool. This is done by
  80. * XORing them into the key which is used to encrypt the pool. Before any
  81. * bytes are retrieved from the pool, the altered key will be used to encrypt
  82. * the whole pool, causing all bits in the pool to depend on the new
  83. * information.
  84. *
  85. * The bits deposited need not have any particular distribution; the stirring
  86. * operation transforms them to uniformly-distributed bits.
  87. */
  88. void
  89. randPoolAddBytes(byte const *buf, unsigned len)
  90. {
  91. byte *p = (byte *)randKey + randKeyAddPos;
  92. unsigned t = sizeof(randKey) - randKeyAddPos;
  93. while (len > t) {
  94. len -= t;
  95. while (t--)
  96. *p++ ^= *buf++;
  97. randPoolStir(); /* sets randKeyAddPos to 0 */
  98. p = (byte *)randKey;
  99. t = sizeof(randKey);
  100. }
  101. if (len) {
  102. randKeyAddPos += len;
  103. do
  104. *p++ ^= *buf++;
  105. while (--len);
  106. randPoolGetPos = sizeof(randPool); /* Force stir on get */
  107. }
  108. }
  109. /*
  110. * Withdraw some bits from the pool. Regardless of the distribution of the
  111. * input bits, the bits returned are uniformly distributed, although they
  112. * cannot, of course, contain more Shannon entropy than the input bits.
  113. */
  114. void
  115. randPoolGetBytes(byte *buf, unsigned len)
  116. {
  117. unsigned t;
  118. while (len > (t = sizeof(randPool) - randPoolGetPos)) {
  119. memcpy(buf, (byte *)randPool+randPoolGetPos, t);
  120. buf += t;
  121. len -= t;
  122. randPoolStir();
  123. }
  124. if (len) {
  125. memcpy(buf, (byte *)randPool+randPoolGetPos, len);
  126. randPoolGetPos += len;
  127. buf += len;
  128. }
  129. }
  130. byte
  131. randPoolGetByte(void)
  132. {
  133. if (randPoolGetPos == sizeof(randPool))
  134. randPoolStir();
  135. return ((byte *)randPool)[randPoolGetPos++];
  136. }