sshrand.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /*
  2. * cryptographic random number generator for PuTTY's ssh client
  3. */
  4. #include "putty.h"
  5. #include "ssh.h"
  6. #include <assert.h>
  7. /* Collect environmental noise every 5 minutes */
  8. #define NOISE_REGULAR_INTERVAL (5*60*TICKSPERSEC)
  9. /*
  10. * `pool' itself is a pool of random data which we actually use: we
  11. * return bytes from `pool', at position `poolpos', until `poolpos'
  12. * reaches the end of the pool. At this point we generate more
  13. * random data, by adding noise, stirring well, and resetting
  14. * `poolpos' to point to just past the beginning of the pool (not
  15. * _the_ beginning, since otherwise we'd give away the whole
  16. * contents of our pool, and attackers would just have to guess the
  17. * next lot of noise).
  18. *
  19. * `incomingb' buffers acquired noise data, until it gets full, at
  20. * which point the acquired noise is SHA'ed into `incoming' and
  21. * `incomingb' is cleared. The noise in `incoming' is used as part
  22. * of the noise for each stirring of the pool, in addition to local
  23. * time, process listings, and other such stuff.
  24. */
  25. #define HASHINPUT 64 /* 64 bytes SHA input */
  26. #define HASHSIZE 20 /* 160 bits SHA output */
  27. #define POOLSIZE 1200 /* size of random pool */
  28. struct RandPool {
  29. unsigned char pool[POOLSIZE];
  30. int poolpos;
  31. unsigned char incoming[HASHSIZE];
  32. unsigned char incomingb[HASHINPUT];
  33. int incomingpos;
  34. bool stir_pending;
  35. };
  36. int random_active = 0;
  37. #ifdef FUZZING
  38. /*
  39. * Special dummy version of the RNG for use when fuzzing.
  40. */
  41. void random_add_noise(NoiseSourceId source, const void *noise, int length) { }
  42. void random_ref(void) { }
  43. void random_unref(void) { }
  44. void random_read(void *out, size_t size)
  45. {
  46. return 0x45; /* Chosen by eight fair coin tosses */
  47. memset(out, 0x45, size); /* Chosen by eight fair coin tosses */
  48. }
  49. void random_get_savedata(void **data, int *len) { }
  50. #else /* !FUZZING */
  51. static struct RandPool pool;
  52. long next_noise_collection;
  53. #ifdef RANDOM_DIAGNOSTICS
  54. int random_diagnostics = 0;
  55. #endif
  56. static void random_stir(void)
  57. {
  58. uint32_t block[HASHINPUT / sizeof(uint32_t)];
  59. uint32_t digest[HASHSIZE / sizeof(uint32_t)];
  60. int i, j, k;
  61. /*
  62. * noise_get_light will call random_add_noise, which may call
  63. * back to here. Prevent recursive stirs.
  64. */
  65. if (pool.stir_pending)
  66. return;
  67. pool.stir_pending = true;
  68. noise_get_light(random_add_noise);
  69. #ifdef RANDOM_DIAGNOSTICS
  70. {
  71. int p, q;
  72. printf("random stir starting\npool:\n");
  73. for (p = 0; p < POOLSIZE; p += HASHSIZE) {
  74. printf(" ");
  75. for (q = 0; q < HASHSIZE; q += 4) {
  76. printf(" %08x", *(uint32_t *)(pool.pool + p + q));
  77. }
  78. printf("\n");
  79. }
  80. printf("incoming:\n ");
  81. for (q = 0; q < HASHSIZE; q += 4) {
  82. printf(" %08x", *(uint32_t *)(pool.incoming + q));
  83. }
  84. printf("\nincomingb:\n ");
  85. for (q = 0; q < HASHINPUT; q += 4) {
  86. printf(" %08x", *(uint32_t *)(pool.incomingb + q));
  87. }
  88. printf("\n");
  89. random_diagnostics++;
  90. }
  91. #endif
  92. SHATransform((uint32_t *) pool.incoming, (uint32_t *) pool.incomingb);
  93. pool.incomingpos = 0;
  94. /*
  95. * Chunks of this code are blatantly endianness-dependent, but
  96. * as it's all random bits anyway, WHO CARES?
  97. */
  98. memcpy(digest, pool.incoming, sizeof(digest));
  99. /*
  100. * Make two passes over the pool.
  101. */
  102. for (i = 0; i < 2; i++) {
  103. /*
  104. * We operate SHA in CFB mode, repeatedly adding the same
  105. * block of data to the digest. But we're also fiddling
  106. * with the digest-so-far, so this shouldn't be Bad or
  107. * anything.
  108. */
  109. memcpy(block, pool.pool, sizeof(block));
  110. /*
  111. * Each pass processes the pool backwards in blocks of
  112. * HASHSIZE, just so that in general we get the output of
  113. * SHA before the corresponding input, in the hope that
  114. * things will be that much less predictable that way
  115. * round, when we subsequently return bytes ...
  116. */
  117. for (j = POOLSIZE; (j -= HASHSIZE) >= 0;) {
  118. /*
  119. * XOR the bit of the pool we're processing into the
  120. * digest.
  121. */
  122. for (k = 0; k < lenof(digest); k++)
  123. digest[k] ^= ((uint32_t *) (pool.pool + j))[k];
  124. /*
  125. * Munge our unrevealed first block of the pool into
  126. * it.
  127. */
  128. SHATransform(digest, block);
  129. /*
  130. * Stick the result back into the pool.
  131. */
  132. for (k = 0; k < lenof(digest); k++)
  133. ((uint32_t *) (pool.pool + j))[k] = digest[k];
  134. }
  135. #ifdef RANDOM_DIAGNOSTICS
  136. if (i == 0) {
  137. int p, q;
  138. printf("random stir midpoint\npool:\n");
  139. for (p = 0; p < POOLSIZE; p += HASHSIZE) {
  140. printf(" ");
  141. for (q = 0; q < HASHSIZE; q += 4) {
  142. printf(" %08x", *(uint32_t *)(pool.pool + p + q));
  143. }
  144. printf("\n");
  145. }
  146. printf("incoming:\n ");
  147. for (q = 0; q < HASHSIZE; q += 4) {
  148. printf(" %08x", *(uint32_t *)(pool.incoming + q));
  149. }
  150. printf("\nincomingb:\n ");
  151. for (q = 0; q < HASHINPUT; q += 4) {
  152. printf(" %08x", *(uint32_t *)(pool.incomingb + q));
  153. }
  154. printf("\n");
  155. }
  156. #endif
  157. }
  158. /*
  159. * Might as well save this value back into `incoming', just so
  160. * there'll be some extra bizarreness there.
  161. */
  162. SHATransform(digest, block);
  163. memcpy(pool.incoming, digest, sizeof(digest));
  164. pool.poolpos = sizeof(pool.incoming);
  165. pool.stir_pending = false;
  166. #ifdef RANDOM_DIAGNOSTICS
  167. {
  168. int p, q;
  169. printf("random stir done\npool:\n");
  170. for (p = 0; p < POOLSIZE; p += HASHSIZE) {
  171. printf(" ");
  172. for (q = 0; q < HASHSIZE; q += 4) {
  173. printf(" %08x", *(uint32_t *)(pool.pool + p + q));
  174. }
  175. printf("\n");
  176. }
  177. printf("incoming:\n ");
  178. for (q = 0; q < HASHSIZE; q += 4) {
  179. printf(" %08x", *(uint32_t *)(pool.incoming + q));
  180. }
  181. printf("\nincomingb:\n ");
  182. for (q = 0; q < HASHINPUT; q += 4) {
  183. printf(" %08x", *(uint32_t *)(pool.incomingb + q));
  184. }
  185. printf("\n");
  186. random_diagnostics--;
  187. }
  188. #endif
  189. }
  190. void random_add_noise(NoiseSourceId source, const void *noise, int length)
  191. {
  192. unsigned char *p = noise;
  193. int i;
  194. if (!random_active)
  195. return;
  196. /*
  197. * This function processes HASHINPUT bytes into only HASHSIZE
  198. * bytes, so _if_ we were getting incredibly high entropy
  199. * sources then we would be throwing away valuable stuff.
  200. */
  201. while (length >= (HASHINPUT - pool.incomingpos)) {
  202. memcpy(pool.incomingb + pool.incomingpos, p,
  203. HASHINPUT - pool.incomingpos);
  204. p += HASHINPUT - pool.incomingpos;
  205. length -= HASHINPUT - pool.incomingpos;
  206. SHATransform((uint32_t *) pool.incoming, (uint32_t *) pool.incomingb);
  207. for (i = 0; i < HASHSIZE; i++) {
  208. if (pool.poolpos >= POOLSIZE)
  209. pool.poolpos = 0;
  210. pool.pool[pool.poolpos++] ^= pool.incoming[i];
  211. if (pool.poolpos >= POOLSIZE)
  212. pool.poolpos = 0;
  213. }
  214. if (pool.poolpos < HASHSIZE)
  215. random_stir();
  216. pool.incomingpos = 0;
  217. }
  218. #ifdef MPEXT
  219. if (length > 0)
  220. #endif
  221. memcpy(pool.incomingb + pool.incomingpos, p, length);
  222. pool.incomingpos += length;
  223. }
  224. void random_add_heavynoise(void *noise, int length)
  225. {
  226. unsigned char *p = noise;
  227. int i;
  228. while (length >= POOLSIZE) {
  229. for (i = 0; i < POOLSIZE; i++)
  230. pool.pool[i] ^= *p++;
  231. random_stir();
  232. length -= POOLSIZE;
  233. }
  234. for (i = 0; i < length; i++)
  235. pool.pool[i] ^= *p++;
  236. random_stir();
  237. }
  238. static void random_add_heavynoise_bitbybit(void *noise, int length)
  239. {
  240. unsigned char *p = noise;
  241. int i;
  242. while (length >= POOLSIZE - pool.poolpos) {
  243. for (i = 0; i < POOLSIZE - pool.poolpos; i++)
  244. pool.pool[pool.poolpos + i] ^= *p++;
  245. random_stir();
  246. length -= POOLSIZE - pool.poolpos;
  247. pool.poolpos = 0;
  248. }
  249. for (i = 0; i < length; i++)
  250. pool.pool[i] ^= *p++;
  251. pool.poolpos = i;
  252. }
  253. static void random_timer(void *ctx, unsigned long now)
  254. {
  255. if (random_active > 0 && now == next_noise_collection) {
  256. noise_regular();
  257. next_noise_collection =
  258. schedule_timer(NOISE_REGULAR_INTERVAL, random_timer, &pool);
  259. }
  260. }
  261. void random_ref(void)
  262. {
  263. MPEXT_PUTTY_SECTION_ENTER;
  264. if (!random_active) {
  265. memset(&pool, 0, sizeof(pool)); /* just to start with */
  266. noise_get_heavy(random_add_heavynoise_bitbybit);
  267. random_stir();
  268. next_noise_collection =
  269. schedule_timer(NOISE_REGULAR_INTERVAL, random_timer, &pool);
  270. }
  271. random_active++;
  272. MPEXT_PUTTY_SECTION_LEAVE;
  273. }
  274. void random_unref(void)
  275. {
  276. MPEXT_PUTTY_SECTION_ENTER;
  277. assert(random_active > 0);
  278. if (random_active == 1) {
  279. #ifndef MPEXT
  280. // We control this on our own in PuttyFinalize()
  281. random_save_seed();
  282. #endif
  283. expire_timer_context(&pool);
  284. }
  285. random_active--;
  286. MPEXT_PUTTY_SECTION_LEAVE;
  287. }
  288. void random_read(void *vout, size_t size)
  289. {
  290. pinitassert(random_active);
  291. uint8_t *out = (uint8_t *)vout;
  292. MPEXT_PUTTY_SECTION_ENTER;
  293. while (size-- > 0) {
  294. if (pool.poolpos >= POOLSIZE)
  295. random_stir();
  296. *out++ = pool.pool[pool.poolpos++];
  297. }
  298. MPEXT_PUTTY_SECTION_LEAVE;
  299. }
  300. void random_get_savedata(void **data, int *len)
  301. {
  302. void *buf = snewn(POOLSIZE / 2, char);
  303. MPEXT_PUTTY_SECTION_ENTER;
  304. random_stir();
  305. memcpy(buf, pool.pool + pool.poolpos, POOLSIZE / 2);
  306. *len = POOLSIZE / 2;
  307. *data = buf;
  308. random_stir();
  309. MPEXT_PUTTY_SECTION_LEAVE;
  310. }
  311. #endif