random.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  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. * Cryptographic random number generation.
  6. */
  7. #include "first.h"
  8. #include <string.h>
  9. #include "kb.h" /* For kbGet() other stuff */
  10. #include "md5.h"
  11. #include "noise.h"
  12. #include "random.h"
  13. #include "randpool.h"
  14. #include "userio.h"
  15. #include "kludge.h"
  16. /*
  17. * This code uses the randpool.c code to generate random numbers.
  18. * That can be augmented with other techniques, such as the
  19. * ANSI X9.17 generator, but the X9.17 generator uses a key-generating
  20. * key which needs to be obtained from somewhere, and the location is
  21. * not entirely clear. The randpool.c functions are entirely
  22. * adequate; extra layers are for belt-and-suspenders security and
  23. * compliance to standards.
  24. *
  25. * For generating long-lived secret keys, we go one more step:
  26. * actually keep track of (an estimate of) the amount of entropy
  27. * which is in the random number pool, and wait for events until
  28. * the amount of entropy accumulated is enough to make all of the
  29. * bits of the secret key truly random. Of course, the guarantees
  30. * of cryptographic strength still apply even if this estimation
  31. * is faulty.
  32. */
  33. /* Get some random bytes */
  34. void
  35. randBytes(byte *buf, unsigned len)
  36. {
  37. randPoolGetBytes(buf, len);
  38. }
  39. /*
  40. * A handy utility for generating uniformly distributed random numbers
  41. * in a small range.
  42. */
  43. unsigned
  44. randRange(unsigned range)
  45. {
  46. unsigned div, r;
  47. byte b[2];
  48. if (range <= 1)
  49. return 0;
  50. if (range <= 256) {
  51. div = 256/range;
  52. do {
  53. randBytes(b, 1);
  54. r = b[0]/div;
  55. } while (r >= range);
  56. } else {
  57. div = (unsigned)(65536/range);
  58. do {
  59. randBytes(b, 2);
  60. r = ((unsigned)b[0] << 8 | b[1])/div;
  61. } while (r >= range);
  62. }
  63. b[0] = b[1] = 0;
  64. return r;
  65. }
  66. #ifdef UNIX /* Or we have popen() */
  67. /*
  68. * Execute the command "string", adding the entropy from the data thus
  69. * gethered to the random number pool. Because the pool is rather
  70. * slow and we want to encourage the use of lots of data, rather than
  71. * adding the data directly, the MD5 is taken and that is added to the
  72. * pool.
  73. */
  74. int
  75. randSourceSet(char const *string, unsigned len, int pri)
  76. {
  77. FILE *f;
  78. struct MD5Context md5;
  79. char buf[256];
  80. int i;
  81. (void)len; /* string is null-terminated */
  82. (void)pri; /* Use every argument, regardless of priority */
  83. f = popen(string, "r");
  84. if (!f)
  85. return -1;
  86. MD5Init(&md5);
  87. while ((i = fread(buf, 1, sizeof(buf), f)) > 0)
  88. MD5Update(&md5, (unsigned char *)buf, i);
  89. pclose(f);
  90. MD5Final((unsigned char *)buf, &md5);
  91. randPoolAddBytes((unsigned char *)buf, 16);
  92. memset(buf, 0, sizeof(buf));
  93. return 0;
  94. }
  95. #endif
  96. /*
  97. * True random bit handling
  98. */
  99. /*
  100. * Truly random bits are difficult to get and must be carefully hoarded.
  101. * These functions use the randpool.c code to store the entropy, and provide
  102. * some bookkeeping on the count of bits of true (Shannon) entropy available
  103. * in the pool.
  104. *
  105. * For generating ordinary session keys, "as much entropy as you've got"
  106. * is good enough, and no accounting is done, except to get some entropy
  107. * to generate the random number seed file if necessary.
  108. *
  109. * But for generating long-lived secret key components, extraordinary
  110. * measures are called for. In addition to what may have been available
  111. * from the random seed file, random data from timed keystrokes is
  112. * accumulated until enough is available.
  113. *
  114. * An estimate of the number of bits of true (Shannon) entropy in the pool
  115. * is kept in trueRandBits. This is incremented when timed keystrokes
  116. * are available, and decremented when bits are explicitly consumed for
  117. * some purpose or another. This counter is maintained here, scaled by
  118. * FRACBITS to count fractional bits for thoroughness. (Thus, the name
  119. * "trueRandBits" is a bit misleading, since it actually counts sixteenths
  120. * of a bit, but I can't think of a better one.)
  121. *
  122. * randFlush is the pool-stirring function. It is also called to
  123. * obliterate traces of old random bits after prime generation is
  124. * completed. (Primes are the most carefully-guarded values in PGP.)
  125. */
  126. #define FRACBITS 4
  127. #define DERATING 0x28 /* 2.5 bits subtracted for derating */
  128. static word32 trueRandBits = 0; /* Bits of entropy in pool */
  129. /*
  130. * Ensure that the random numbers generated by prior calls to randBytes
  131. * will never be recoverable from the contents of memory. This doesn't
  132. * wipe memory to a fixed value (the entropy might come in handy for future
  133. * operations), it just runs the generators forward enough that the previous
  134. * state is irretrievable.
  135. *
  136. * This is called after prime generation, before the random data is saved
  137. * out, so it is protecting prime data and is particularly paranoid.
  138. */
  139. void
  140. randFlush(void)
  141. {
  142. byte buf[16];
  143. int i;
  144. for (i = 0; i < 3; i++) /* Zipper + Belt + Suspenders */
  145. randPoolStir(); /* Clean pseudo-random generator */
  146. memset(buf, 0, sizeof(buf));
  147. trueRandBits = 0;
  148. }
  149. /*
  150. * Given an event (typically a keystroke) coded by "event" at a random time,
  151. * add all randomness to the random pool, compute a (conservative) estimate
  152. * of the amount, add it to the pool, and return the amount of randomness.
  153. * (The return value is just for informational purposes.)
  154. *
  155. * Double events are okay, but three in a row is considered
  156. * suspicious and the randomness is counted as 0.
  157. *
  158. * As an extra precaution against key repeat or other very regular input
  159. * data, the entropy extimate is derived not from the time interval measured,
  160. * but from the minimum of it and the (absolute) difference between it and
  161. * the previous time interval, i.e. the second-order delta.
  162. */
  163. unsigned
  164. randEvent(int event)
  165. {
  166. static int event1 = 0, event2 = 0; /* Previous events */
  167. static word32 prevdelta; /* Previous delta */
  168. word32 delta; /* Time between last two events */
  169. unsigned cbits; /* Entropy estimate, in bits. */
  170. word32 t; /* Temprary value */
  171. int i;
  172. delta = noise();
  173. randPoolAddBytes((byte *)&event, sizeof(event));
  174. /*
  175. * Don't credit triple events with any entropy on the grounds that
  176. * they're probably something periodic like key repeat. But remember
  177. * the delta.
  178. */
  179. if (event == event1 && event == event2) {
  180. prevdelta = delta;
  181. return 0;
  182. }
  183. event2 = event1;
  184. event1 = event;
  185. /* Compute second-order delta */
  186. t = (delta > prevdelta) ? delta - prevdelta : prevdelta - delta;
  187. /* Remember current delta for next time */
  188. prevdelta = delta;
  189. /* Find minimum of delta and second-order delta */
  190. if (delta > t)
  191. delta = t;
  192. /* Avoid divide-by-zero errors below */
  193. if (!delta)
  194. return 0;
  195. /* Count the number of bits of entropy available - integer log2. */
  196. cbits = 0;
  197. i = 16;
  198. t = 0xffffffff;
  199. do {
  200. t <<= i;
  201. if (delta & t)
  202. cbits += i;
  203. else
  204. delta <<= i;
  205. } while (i >>= 1);
  206. /*
  207. * At this point, delta is normalized and has its high bit set.
  208. * Now count fractional bits, using binary logarithm algorithm
  209. */
  210. for (i = 0; i < FRACBITS; i++) {
  211. cbits <<= 1;
  212. delta >>= 16;
  213. delta *= delta;
  214. if (delta & 0x80000000)
  215. cbits++;
  216. else
  217. delta <<= 1;
  218. }
  219. if (cbits <= DERATING)
  220. return 0; /* nothing */
  221. cbits -= DERATING;
  222. trueRandBits += cbits;
  223. if (trueRandBits > RANDPOOLBITS<<FRACBITS)
  224. trueRandBits = RANDPOOLBITS<<FRACBITS;
  225. return cbits;
  226. }
  227. /*
  228. * Performs an accumulation of random bits. As long as there are
  229. * fewer bits in the buffer than are needed, prompt for more.
  230. * (kbGet is known to call randEvent() which increments trueRandBits.)
  231. */
  232. void
  233. randAccum(unsigned count)
  234. {
  235. word32 randbits = trueRandBits;
  236. noise(); /* Establish a baseline for timing comparisons */
  237. if (count > RANDPOOLBITS)
  238. count = RANDPOOLBITS;
  239. if (randbits>>FRACBITS >= count)
  240. return;
  241. userPrintf("\n\
  242. We need to generate %u random bits. This is done by measuring the\n\
  243. time intervals between your keystrokes. Please enter some random text\n\
  244. on your keyboard until you hear the beep:\n", count - (randbits>>FRACBITS));
  245. kbCbreak();
  246. do {
  247. /* display counter to show progress */
  248. userPrintf(("\r%4u "), count-(unsigned)(randbits>>FRACBITS));
  249. userFlush(); /* ensure screen update */
  250. kbFlush(0); /* Typeahead is illegal */
  251. (void)kbGet(); /* Wait for next char */
  252. /* Print flag indicating acceptance (or not) */
  253. userPutc(trueRandBits == randbits ? '?' : '.');
  254. randbits = trueRandBits;
  255. } while (randbits>>FRACBITS < count);
  256. /* Do final display update */
  257. userPuts(("\r 0 *"));
  258. userPuts("\a -Enough, thank you.\n");
  259. /* Do an extra-thorough flush to absorb extra typing. */
  260. kbFlush(1);
  261. kbNorm();
  262. }