dhtest.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /*
  2. * Copyright (c) 1995 Colin Plumb. All rights reserved.
  3. * For licensing and other legal details, see the file legal.c.
  4. *
  5. * dhtest.c - Diffie-Hellman prime generator.
  6. *
  7. * This generates Diffie-Hellman primes using a (hopefully) clearly
  8. * defined algorithm, based on David Kravitz's "kosherizer".
  9. * This takes a seed in the form of a byte string, usually ASCII.
  10. * The byte string is hashed with SHA. This forms the low 160 bits
  11. * of the search start number. If the desired start number is longer
  12. * than this, the byte string is treated as a big-endian number and
  13. * incremented, which increments the last byte, propagating carry.
  14. * (Modulo the size of the seed itself, which is not an issue in
  15. * practice for any seed at least one byte long.)
  16. * This incremented value is hashed to produce the next most significant
  17. * 160 bits, and so on.
  18. * After enough bits have been accumulated, the low bit is set, the extra
  19. * high bits are masked off to zero, and the two high bits of the
  20. * search start number are set. This is used as a starting seed for a
  21. * sequential (increasing) search for a suitable prime.
  22. *
  23. * A suitable prime P is itself prime, and (P-1)/2 is also prime.
  24. */
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include "bn.h"
  28. #include "germain.h"
  29. #include "sieve.h"
  30. #include "cputime.h"
  31. #include "sha.h"
  32. #define BNDEBUG 1
  33. #if BNDEBUG
  34. #include "bnprint.h"
  35. #define bndPut(prompt, bn) bnPrint(stdout, prompt, bn, "\n")
  36. #define bndPrintf printf
  37. #else
  38. #define bndPut(prompt, bn) ((void)(prompt),(void)(bn))
  39. #define bndPrintf (void)
  40. #endif
  41. /*
  42. * Generate a bignum of a specified length, with the given
  43. * high and low 8 bits. "High" is merged into the high 8 bits of the
  44. * number. For example, set it to 0x80 to ensure that the number is
  45. * exactly "bits" bits long (i.e. 2^(bits-1) <= bn < 2^bits).
  46. * "Low" is merged into the low 8 bits. For example, set it to
  47. * 1 to ensure that you generate an odd number.
  48. *
  49. * The bignum is generated using the given seed string. The
  50. * technique is from David Kravitz (of the NSA)'s "kosherizer".
  51. * The string is hashed, and that (with the low bit forced to 1)
  52. * is used for the low 160 bits of the number. Then the string,
  53. * considered as a big-endian array of bytes, is incremented
  54. * and the incremented value is hashed to produce the next most
  55. * significant 160 bits, and so on. The increment is performed
  56. * modulo the size of the seed string.
  57. *
  58. * The most significant *two* bits are forced to 1, the first to
  59. * ensure that the number is long enough, and the second just to
  60. * place the prime in the high half of the range to make breaking
  61. * it slightly more difficult, since it makes essentially no
  62. * difference to the use of the number.
  63. */
  64. static int
  65. genRandBn(struct BigNum *bn, unsigned bits, unsigned char high,
  66. unsigned char low, unsigned char *seed, unsigned len)
  67. {
  68. unsigned char buf[SHA_DIGESTSIZE];
  69. unsigned bytes;
  70. unsigned l = 0; /* Current position */
  71. unsigned i;
  72. struct SHAContext sha;
  73. bnSetQ(bn, 0);
  74. bytes = (bits+7) / 8; /* Number of bytes to use */
  75. shaInit(&sha);
  76. shaUpdate(&sha, seed, len);
  77. shaFinal(&sha, buf);
  78. buf[SHA_DIGESTSIZE-1] |= low;
  79. while (bytes > SHA_DIGESTSIZE) {
  80. bytes -= SHA_DIGESTSIZE;
  81. /* Merge in low half of high bits, if necessary */
  82. if (bytes == 1 && (bits & 7))
  83. buf[0] |= high << (bits & 7);
  84. if (bnInsertBigBytes(bn, buf, l, SHA_DIGESTSIZE) < 0)
  85. return -1;
  86. l += SHA_DIGESTSIZE;
  87. /* Increment the seed, ignoring carry out. */
  88. i = len;
  89. while (i--) {
  90. if (++seed[i] & 255)
  91. break; /* Didn't wrap; done */
  92. }
  93. shaInit(&sha);
  94. shaUpdate(&sha, seed, len);
  95. shaFinal(&sha, buf);
  96. }
  97. /* Do the final "bytes"-long section, using the tail bytes in buf */
  98. /* Mask off excess high bits */
  99. buf[SHA_DIGESTSIZE-bytes] &= 255 >> (-bits & 7);
  100. /* Merge in specified high bits */
  101. buf[SHA_DIGESTSIZE-bytes] |= high >> (-bits & 7);
  102. if (bytes > 1 && (bits & 7))
  103. buf[SHA_DIGESTSIZE-bytes+1] |= high << (bits & 7);
  104. /* Merge in the appropriate bytes of the buffer */
  105. if (bnInsertBigBytes(bn, buf+SHA_DIGESTSIZE-bytes, l, bytes) < 0)
  106. return -1;
  107. return 0;
  108. }
  109. struct Progress {
  110. FILE *f;
  111. unsigned column;
  112. unsigned wrap;
  113. };
  114. static int
  115. genProgress(void *arg, int c)
  116. {
  117. struct Progress *p = arg;
  118. if (++p->column > p->wrap) {
  119. putc('\n', p->f);
  120. p->column = 1;
  121. }
  122. putc(c, p->f);
  123. fflush(p->f);
  124. return 0;
  125. }
  126. static int
  127. genDH(struct BigNum *bn, unsigned bits, unsigned char *seed, unsigned len,
  128. FILE *f)
  129. {
  130. #if CLOCK_AVAIL
  131. timetype start, stop;
  132. unsigned long s;
  133. #endif
  134. int i;
  135. unsigned char s1[1024], s2[1024];
  136. unsigned p1, p2;
  137. struct BigNum step;
  138. struct Progress progress;
  139. if (f)
  140. fprintf(f, "Generating a %u-bit D-H prime with \"%.*s\"\n",
  141. bits, (int)len, (char *)seed);
  142. progress.f = f;
  143. progress.column = 0;
  144. progress.wrap = 78;
  145. /* Find p - choose a starting place */
  146. if (genRandBn(bn, bits, 0xC0, 3, seed, len) < 0)
  147. return -1;
  148. #if BNDEBUG /* DEBUG - check that sieve works properly */
  149. bnBegin(&step);
  150. bnSetQ(&step, 2);
  151. sieveBuild(s1, 1024, bn, 2, 0);
  152. sieveBuildBig(s2, 1024, bn, &step, 0);
  153. p1 = p2 = 0;
  154. if (s1[0] != s2[0])
  155. printf("Difference: s1[0] = %x s2[0] = %x\n", s1[0], s2[0]);
  156. do {
  157. p1 = sieveSearch(s1, 1024, p1);
  158. p2 = sieveSearch(s2, 1024, p2);
  159. if (p1 != p2)
  160. printf("Difference: p1 = %u p2 = %u\n", p1, p2);
  161. } while (p1 && p2);
  162. bnEnd(&step);
  163. #endif
  164. /* And search for a prime */
  165. #if CLOCK_AVAIL
  166. gettime(&start);
  167. #endif
  168. i = germainPrimeGen(bn, 1, f ? genProgress : 0, (void *)&progress);
  169. if (i < 0)
  170. return -1;
  171. #if CLOCK_AVAIL
  172. gettime(&stop);
  173. #endif
  174. if (f) {
  175. putc('\n', f);
  176. fprintf(f, "%d modular exponentiations performed.\n", i);
  177. }
  178. #if CLOCK_AVAIL
  179. subtime(stop, start);
  180. s = sec(stop);
  181. bndPrintf("%u-bit time = %lu.%03u sec.", bits, s, msec(stop));
  182. if (s > 60) {
  183. putchar(' ');
  184. putchar('(');
  185. if (s > 3600)
  186. printf("%u:%02u", (unsigned)(s/3600),
  187. (unsigned)(s/60%60));
  188. else
  189. printf("%u", (unsigned)(s/60));
  190. printf(":%02u)", (unsigned)(s%60));
  191. }
  192. putchar('\n');
  193. #endif
  194. bndPut("p = ", bn);
  195. return 0;
  196. }
  197. static int
  198. testDH(struct BigNum *bn)
  199. {
  200. struct BigNum pub1, pub2, sec1, sec2;
  201. unsigned bits;
  202. int i = 0;
  203. char buf[4];
  204. bnBegin(&pub1);
  205. bnBegin(&pub2);
  206. bnBegin(&sec1);
  207. bnBegin(&sec2);
  208. /* Bits of secret - add a few to ensure an even distribution */
  209. bits = bnBits(bn)+4;
  210. /* Temporarily decrement bn for some operations */
  211. (void)bnSubQ(bn, 1);
  212. strcpy(buf, "foo");
  213. i = genRandBn(&sec1, bits, 0, 0, (unsigned char *)buf, 4);
  214. if (i < 0)
  215. goto done;
  216. /* Reduce sec1 to the correct range */
  217. i = bnMod(&sec1, &sec1, bn);
  218. if (i < 0)
  219. goto done;
  220. strcpy(buf, "bar");
  221. i = genRandBn(&sec2, bits, 0, 0, (unsigned char *)buf, 4);
  222. if (i < 0)
  223. goto done;
  224. /* Reduce sec2 to the correct range */
  225. i = bnMod(&sec2, &sec2, bn);
  226. if (i < 0)
  227. goto done;
  228. /* Re-increment bn */
  229. (void)bnAddQ(bn, 1);
  230. puts("Doing first half for party 1");
  231. i = bnTwoExpMod(&pub1, &sec1, bn);
  232. if (i < 0)
  233. goto done;
  234. puts("Doing first half for party 2");
  235. i = bnTwoExpMod(&pub2, &sec2, bn);
  236. if (i < 0)
  237. goto done;
  238. /* In a real protocol, pub1 and pub2 are now exchanged */
  239. puts("Doing second half for party 1");
  240. i = bnExpMod(&pub2, &pub2, &sec1, bn);
  241. if (i < 0)
  242. goto done;
  243. bndPut("shared = ", &pub2);
  244. puts("Doing second half for party 2");
  245. i = bnExpMod(&pub1, &pub1, &sec2, bn);
  246. if (i < 0)
  247. goto done;
  248. bndPut("shared = ", &pub1);
  249. if (bnCmp(&pub1, &pub2) != 0) {
  250. puts("Diffie-Hellman failed!");
  251. i = -1;
  252. } else {
  253. puts("Test successful.");
  254. }
  255. done:
  256. bnEnd(&sec2);
  257. bnEnd(&sec1);
  258. bnEnd(&pub2);
  259. bnEnd(&pub1);
  260. return i;
  261. }
  262. /* Copy the command line to the buffer. */
  263. static unsigned
  264. copy(unsigned char *buf, int argc, char **argv)
  265. {
  266. unsigned pos, len;
  267. pos = 0;
  268. while (--argc) {
  269. len = strlen(*++argv);
  270. memcpy(buf, *argv, len);
  271. buf += len;
  272. pos += len;
  273. if (argc > 1) {
  274. *buf++ = ' ';
  275. pos++;
  276. }
  277. }
  278. return pos;
  279. }
  280. int
  281. main(int argc, char **argv)
  282. {
  283. unsigned len;
  284. struct BigNum bn;
  285. unsigned char buf[1024];
  286. if (argc < 2) {
  287. fprintf(stderr, "Usage: %s <seed>\n", argv[0]);
  288. fputs("\
  289. <seed> should be a a string of bytes to be hashed to seed the prime\n\
  290. generator. Note that unquoted whitespace between words will be counted\n\
  291. as a single space. To include multiple spaces, quote them.\n", stderr);
  292. return 1;
  293. }
  294. bnInit();
  295. bnBegin(&bn);
  296. len = copy(buf, argc, argv);
  297. genDH(&bn, 0x100, buf, len, stdout);
  298. testDH(&bn);
  299. len = copy(buf, argc, argv);
  300. genDH(&bn, 0x200, buf, len, stdout);
  301. testDH(&bn);
  302. len = copy(buf, argc, argv);
  303. genDH(&bn, 0x300, buf, len, stdout);
  304. testDH(&bn);
  305. len = copy(buf, argc, argv);
  306. genDH(&bn, 0x400, buf, len, stdout);
  307. testDH(&bn);
  308. len = copy(buf, argc, argv);
  309. genDH(&bn, 0x500, buf, len, stdout);
  310. testDH(&bn);
  311. #if 0
  312. /* These get *really* slow */
  313. len = copy(buf, argc, argv);
  314. genDH(&bn, 0x600, buf, len, stdout);
  315. testDH(&bn);
  316. len = copy(buf, argc, argv);
  317. genDH(&bn, 0x800, buf, len, stdout);
  318. testDH(&bn);
  319. len = copy(buf, argc, argv);
  320. genDH(&bn, 0xc00, buf, len, stdout);
  321. testDH(&bn);
  322. /* Like, plan on a *week* or more for this one. */
  323. len = copy(buf, argc, argv);
  324. genDH(&bn, 0x1000, buf, len, stdout);
  325. testDH(&bn);
  326. #endif
  327. bnEnd(&bn);
  328. return 0;
  329. }