prng.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /*
  2. * PuTTY's cryptographic pseudorandom number generator.
  3. *
  4. * This module just defines the PRNG object type and its methods. The
  5. * usual global instance of it is managed by sshrand.c.
  6. */
  7. #include "putty.h"
  8. #include "ssh.h"
  9. #include "mpint_i.h"
  10. #ifdef PRNG_DIAGNOSTICS
  11. #define prngdebug debug
  12. #else
  13. #define prngdebug(...) ((void)0)
  14. #endif
  15. /*
  16. * This random number generator is based on the 'Fortuna' design by
  17. * Niels Ferguson and Bruce Schneier. The biggest difference is that I
  18. * use SHA-256 in place of a block cipher: the generator side of the
  19. * system works by computing HASH(key || counter) instead of
  20. * ENCRYPT(counter, key).
  21. *
  22. * Rationale: the Fortuna description itself suggests that using
  23. * SHA-256 would be nice but people wouldn't accept it because it's
  24. * too slow - but PuTTY isn't a heavy enough user of random numbers to
  25. * make that a serious worry. In fact even with SHA-256 this generator
  26. * is faster than the one we previously used. Also the Fortuna
  27. * description worries about periodic rekeying to avoid the barely
  28. * detectable pattern of never repeating a cipher block - but with
  29. * SHA-256, even that shouldn't be a worry, because the output
  30. * 'blocks' are twice the size, and also SHA-256 has no guarantee of
  31. * bijectivity, so it surely _could_ be possible to generate the same
  32. * block from two counter values. Thirdly, Fortuna has to have a hash
  33. * function anyway, for reseeding and entropy collection, so reusing
  34. * the same one means it only depends on one underlying primitive and
  35. * can be easily reinstantiated with a larger hash function if you
  36. * decide you'd like to do that on a particular occasion.
  37. */
  38. #define NCOLLECTORS 32
  39. #define RESEED_DATA_SIZE 64
  40. typedef struct prng_impl prng_impl;
  41. struct prng_impl {
  42. prng Prng;
  43. const ssh_hashalg *hashalg;
  44. /*
  45. * Generation side:
  46. *
  47. * 'generator' is a hash object with the current key preloaded
  48. * into it. The counter-mode generation is achieved by copying
  49. * that hash object, appending the counter value to the copy, and
  50. * calling ssh_hash_final.
  51. */
  52. ssh_hash *generator;
  53. BignumInt counter[128 / BIGNUM_INT_BITS];
  54. /*
  55. * When re-seeding the generator, you call prng_seed_begin(),
  56. * which sets up a hash object in 'keymaker'. You write your new
  57. * seed data into it (which you can do by calling put_data on the
  58. * PRNG object itself) and then call prng_seed_finish(), which
  59. * finalises this hash and uses the output to set up the new
  60. * generator.
  61. *
  62. * The keymaker hash preimage includes the previous key, so if you
  63. * just want to change keys for the sake of not keeping the same
  64. * one for too long, you don't have to put any extra seed data in
  65. * at all.
  66. */
  67. ssh_hash *keymaker;
  68. /*
  69. * Collection side:
  70. *
  71. * There are NCOLLECTORS hash objects collecting entropy. Each
  72. * separately numbered entropy source puts its output into those
  73. * hash objects in the order 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,...,
  74. * that is to say, each entropy source has a separate counter
  75. * which is incremented every time that source generates an event,
  76. * and the event data is added to the collector corresponding to
  77. * the index of the lowest set bit in the current counter value.
  78. *
  79. * Whenever collector #0 has at least RESEED_DATA_SIZE bytes (and
  80. * it's not at least 100ms since the last reseed), the PRNG is
  81. * reseeded, with seed data on reseed #n taken from the first j
  82. * collectors, where j is one more than the number of factors of 2
  83. * in n. That is, collector #0 is used in every reseed; #1 in
  84. * every other one, #2 in every fourth, etc.
  85. *
  86. * 'until_reseed' counts the amount of data that still needs to be
  87. * added to collector #0 before a reseed will be triggered.
  88. */
  89. uint32_t source_counters[NOISE_MAX_SOURCES];
  90. ssh_hash *collectors[NCOLLECTORS];
  91. size_t until_reseed;
  92. uint32_t reseeds;
  93. uint64_t last_reseed_time;
  94. };
  95. static void prng_seed_BinarySink_write(
  96. BinarySink *bs, const void *data, size_t len);
  97. prng *prng_new(const ssh_hashalg *hashalg)
  98. {
  99. prng_impl *pi = snew(prng_impl);
  100. memset(pi, 0, sizeof(prng_impl));
  101. pi->hashalg = hashalg;
  102. pi->keymaker = NULL;
  103. pi->generator = NULL;
  104. memset(pi->counter, 0, sizeof(pi->counter));
  105. { // WINSCP
  106. size_t i; // WINSCP
  107. for (i = 0; i < NCOLLECTORS; i++)
  108. pi->collectors[i] = ssh_hash_new(pi->hashalg);
  109. pi->until_reseed = 0;
  110. BinarySink_INIT(&pi->Prng, prng_seed_BinarySink_write);
  111. pi->Prng.savesize = pi->hashalg->hlen * 4;
  112. return &pi->Prng;
  113. } // WINSCP
  114. }
  115. void prng_free(prng *pr)
  116. {
  117. prng_impl *pi = container_of(pr, prng_impl, Prng);
  118. smemclr(pi->counter, sizeof(pi->counter));
  119. { // WINSCP
  120. size_t i; // WINSCP
  121. for (i = 0; i < NCOLLECTORS; i++)
  122. ssh_hash_free(pi->collectors[i]);
  123. if (pi->generator)
  124. ssh_hash_free(pi->generator);
  125. if (pi->keymaker)
  126. ssh_hash_free(pi->keymaker);
  127. smemclr(pi, sizeof(*pi));
  128. sfree(pi);
  129. } // WINSCP
  130. }
  131. void prng_seed_begin(prng *pr)
  132. {
  133. prng_impl *pi = container_of(pr, prng_impl, Prng);
  134. assert(!pi->keymaker);
  135. prngdebug("prng: reseed begin\n");
  136. /*
  137. * Make a hash instance that will generate the key for the new one.
  138. */
  139. if (pi->generator) {
  140. pi->keymaker = pi->generator;
  141. pi->generator = NULL;
  142. } else {
  143. pi->keymaker = ssh_hash_new(pi->hashalg);
  144. }
  145. put_byte(pi->keymaker, 'R');
  146. }
  147. static void prng_seed_BinarySink_write(
  148. BinarySink *bs, const void *data, size_t len)
  149. {
  150. prng *pr = BinarySink_DOWNCAST(bs, prng);
  151. prng_impl *pi = container_of(pr, prng_impl, Prng);
  152. assert(pi->keymaker);
  153. prngdebug("prng: got %"SIZEu" bytes of seed\n", len);
  154. put_data(pi->keymaker, data, len);
  155. }
  156. void prng_seed_finish(prng *pr)
  157. {
  158. prng_impl *pi = container_of(pr, prng_impl, Prng);
  159. unsigned char buf[MAX_HASH_LEN];
  160. assert(pi->keymaker);
  161. prngdebug("prng: reseed finish\n");
  162. /*
  163. * Actually generate the key.
  164. */
  165. ssh_hash_final(pi->keymaker, buf);
  166. pi->keymaker = NULL;
  167. /*
  168. * Load that key into a fresh hash instance, which will become the
  169. * new generator.
  170. */
  171. assert(!pi->generator);
  172. pi->generator = ssh_hash_new(pi->hashalg);
  173. put_data(pi->generator, buf, pi->hashalg->hlen);
  174. pi->until_reseed = RESEED_DATA_SIZE;
  175. pi->last_reseed_time = prng_reseed_time_ms();
  176. smemclr(buf, sizeof(buf));
  177. }
  178. static inline void prng_generate(prng_impl *pi, void *outbuf)
  179. {
  180. ssh_hash *h = ssh_hash_copy(pi->generator);
  181. prngdebug("prng_generate\n");
  182. put_byte(h, 'G');
  183. { // WINSCP
  184. unsigned i; // WINSCP
  185. for (i = 0; i < 128; i += 8)
  186. put_byte(h, pi->counter[i/BIGNUM_INT_BITS] >> (i%BIGNUM_INT_BITS));
  187. { // WINSCP
  188. BignumCarry c = 1;
  189. for (i = 0; i < lenof(pi->counter); i++)
  190. BignumADC(pi->counter[i], c, pi->counter[i], 0, c);
  191. ssh_hash_final(h, outbuf);
  192. } // WINSCP
  193. } // WINSCP
  194. }
  195. void prng_read(prng *pr, void *vout, size_t size)
  196. {
  197. prng_impl *pi = container_of(pr, prng_impl, Prng);
  198. unsigned char buf[MAX_HASH_LEN];
  199. assert(!pi->keymaker);
  200. prngdebug("prng_read %"SIZEu"\n", size);
  201. { // WINSCP
  202. uint8_t *out = (uint8_t *)vout;
  203. while (size > 0) {
  204. prng_generate(pi, buf);
  205. { // WINSCP
  206. size_t to_use = size > pi->hashalg->hlen ? pi->hashalg->hlen : size;
  207. memcpy(out, buf, to_use);
  208. out += to_use;
  209. size -= to_use;
  210. } // WINSCP
  211. }
  212. smemclr(buf, sizeof(buf));
  213. prng_seed_begin(&pi->Prng);
  214. prng_seed_finish(&pi->Prng);
  215. } // WINSCP
  216. }
  217. void prng_add_entropy(prng *pr, unsigned source_id, ptrlen data)
  218. {
  219. prng_impl *pi = container_of(pr, prng_impl, Prng);
  220. pinitassert(source_id < NOISE_MAX_SOURCES);
  221. uint32_t counter = ++pi->source_counters[source_id];
  222. size_t index = 0;
  223. while (index+1 < NCOLLECTORS && !(counter & 1)) {
  224. counter >>= 1;
  225. index++;
  226. }
  227. prngdebug("prng_add_entropy source=%u size=%"SIZEu" -> collector %zi\n",
  228. source_id, data.len, index);
  229. put_datapl(pi->collectors[index], data);
  230. if (index == 0)
  231. pi->until_reseed = (pi->until_reseed < data.len ? 0 :
  232. pi->until_reseed - data.len);
  233. if (pi->until_reseed == 0 &&
  234. prng_reseed_time_ms() - pi->last_reseed_time >= 100) {
  235. prng_seed_begin(&pi->Prng);
  236. { // WINSCP
  237. unsigned char buf[MAX_HASH_LEN];
  238. uint32_t reseed_index = ++pi->reseeds;
  239. prngdebug("prng entropy reseed #%"PRIu32"\n", reseed_index);
  240. { // WINSCP
  241. size_t i; // WINSCP
  242. for (i = 0; i < NCOLLECTORS; i++) {
  243. prngdebug("emptying collector %"SIZEu"\n", i);
  244. ssh_hash_digest(pi->collectors[i], buf);
  245. put_data(&pi->Prng, buf, pi->hashalg->hlen);
  246. ssh_hash_reset(pi->collectors[i]);
  247. if (reseed_index & 1)
  248. break;
  249. reseed_index >>= 1;
  250. }
  251. smemclr(buf, sizeof(buf));
  252. prng_seed_finish(&pi->Prng);
  253. } // WINSCP
  254. } // WINSCP
  255. }
  256. }
  257. size_t prng_seed_bits(prng *pr)
  258. {
  259. prng_impl *pi = container_of(pr, prng_impl, Prng);
  260. return pi->hashalg->hlen * 8;
  261. }