dsatest.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. /*
  2. * Copyright (c) 1995 Colin Plumb. All rights reserved.
  3. * For licensing and other legal details, see the file legal.c.
  4. *
  5. * dsatest.c - DSA key generator and test driver.
  6. *
  7. * This generates DSA primes using a (hopefully) clearly
  8. * defined algorithm, based on David Kravitz's "kosherizer".
  9. * It is not, however, identical.
  10. */
  11. #include <stdio.h>
  12. #include <string.h>
  13. #include "bn.h"
  14. #include "prime.h"
  15. #include "cputime.h"
  16. #include "sha.h"
  17. #define BNDEBUG 1
  18. #if BNDEBUG
  19. #include "bnprint.h"
  20. #define bndPut(prompt, bn) bnPrint(stdout, prompt, bn, "\n")
  21. #define bndPrintf printf
  22. #else
  23. #define bndPut(prompt, bn) ((void)(prompt),(void)(bn))
  24. #define bndPrintf (void)
  25. #endif
  26. /*
  27. * Generate a bignum of a specified length, with the given
  28. * high and low 8 bits. "High" is merged into the high 8 bits of the
  29. * number. For example, set it to 0x80 to ensure that the number is
  30. * exactly "bits" bits long (i.e. 2^(bits-1) <= bn < 2^bits).
  31. * "Low" is merged into the low 8 bits. For example, set it to
  32. * 1 to ensure that you generate an odd number.
  33. *
  34. * Then XOR the result into the input bignum. This is to
  35. * accomodate the kosherizer in all its generality.
  36. *
  37. * The bignum is generated using the given seed string. The
  38. * technique is from David Kravitz (of the NSA)'s "kosherizer".
  39. * The string is hashed, and that (with the low bit forced to 1)
  40. * is used for the low 160 bits of the number. Then the string,
  41. * considered as a big-endian array of bytes, is incremented
  42. * and the incremented value is hashed to produce the next most
  43. * significant 160 bits, and so on. The increment is performed
  44. * modulo the size of the seed string.
  45. *
  46. * The seed is returned incremented so that it may be used to generate
  47. * subsequent numbers.
  48. *
  49. * The most and least significant 8 bits of the returned number are forced
  50. * to the values passed in "high" and "low", respectively. Typically,
  51. * high would be set to 0x80 to force the most significant bit to 1.
  52. */
  53. static int
  54. genRandBn(struct BigNum *bn, unsigned bits, unsigned char high,
  55. unsigned char low, unsigned char *seed, unsigned len)
  56. {
  57. unsigned char buf1[SHA_DIGESTSIZE];
  58. unsigned char buf2[SHA_DIGESTSIZE];
  59. unsigned bytes = (bits+7)/8;
  60. unsigned l = 0; /* Current position */
  61. unsigned i;
  62. struct SHAContext sha;
  63. if (!bits)
  64. return 0;
  65. /* Generate the first bunch of hashed data */
  66. shaInit(&sha);
  67. shaUpdate(&sha, seed, len);
  68. shaFinal(&sha, buf1);
  69. /* Increment the seed, ignoring carry out. */
  70. i = len;
  71. while (i-- && (++seed[i] & 255) == 0)
  72. ;
  73. /* XOR in the existing bytes */
  74. bnExtractBigBytes(bn, buf2, l, SHA_DIGESTSIZE);
  75. for (i = 0; i < SHA_DIGESTSIZE; i++)
  76. buf1[i] ^= buf2[i];
  77. buf1[SHA_DIGESTSIZE-1] |= low;
  78. while (bytes > SHA_DIGESTSIZE) {
  79. bytes -= SHA_DIGESTSIZE;
  80. /* Merge in low half of high bits, if necessary */
  81. if (bytes == 1 && (bits & 7))
  82. buf1[0] |= high << (bits & 7);
  83. if (bnInsertBigBytes(bn, buf1, l, SHA_DIGESTSIZE) < 0)
  84. return -1;
  85. l += SHA_DIGESTSIZE;
  86. /* Compute the next hash we need */
  87. shaInit(&sha);
  88. shaUpdate(&sha, seed, len);
  89. shaFinal(&sha, buf1);
  90. /* Increment the seed, ignoring carry out. */
  91. i = len;
  92. while (i-- && (++seed[i] & 255) == 0)
  93. ;
  94. /* XOR in the existing bytes */
  95. bnExtractBigBytes(bn, buf2, l, SHA_DIGESTSIZE);
  96. for (i = 0; i < SHA_DIGESTSIZE; i++)
  97. buf1[i] ^= buf2[i];
  98. }
  99. /* Do the final "bytes"-long section, using the tail bytes in buf1 */
  100. /* Mask off excess high bits */
  101. buf1[SHA_DIGESTSIZE-bytes] &= 255 >> (-bits & 7);
  102. /* Merge in specified high bits */
  103. buf1[SHA_DIGESTSIZE-bytes] |= high >> (-bits & 7);
  104. if (bytes > 1 && (bits & 7))
  105. buf1[SHA_DIGESTSIZE-bytes+1] |= high << (bits & 7);
  106. /* Merge in the appropriate bytes of the buffer */
  107. if (bnInsertBigBytes(bn, buf1+SHA_DIGESTSIZE-bytes, l, bytes) < 0)
  108. return -1;
  109. return 0;
  110. }
  111. struct Progress {
  112. FILE *f;
  113. unsigned column;
  114. unsigned wrap;
  115. };
  116. static int
  117. genProgress(void *arg, int c)
  118. {
  119. struct Progress *p = arg;
  120. if (++p->column > p->wrap) {
  121. putc('\n', p->f);
  122. p->column = 1;
  123. }
  124. putc(c, p->f);
  125. fflush(p->f);
  126. return 0;
  127. }
  128. static int
  129. dsaGen(struct BigNum *p, unsigned pbits, struct BigNum *q, unsigned qbits,
  130. struct BigNum *g, struct BigNum *x, struct BigNum *y,
  131. unsigned char *seed, unsigned len, FILE *f)
  132. {
  133. struct BigNum h, e;
  134. int i;
  135. #if CLOCK_AVAIL
  136. timetype start, stop;
  137. unsigned long s;
  138. #endif
  139. struct Progress progress;
  140. if (f)
  141. fprintf(f,
  142. "Generating a DSA key pair with %u-bit p and %u-bit q,\n"
  143. "seed = \"%.*s\"\n", pbits, qbits, (int)len, (char *)seed);
  144. progress.f = f;
  145. progress.column = 0;
  146. progress.wrap = 78;
  147. #if CLOCK_AVAIL
  148. gettime(&start);
  149. #endif
  150. /*
  151. * Choose a random starting place for q
  152. * Starting place is SHA(seed) XOR SHA(seed+1),
  153. * With the high *8* bits set to 1.
  154. */
  155. (void)bnSetQ(q, 0);
  156. if (genRandBn(q, qbits, 0xFF, 0, seed, len) < 0)
  157. return -1;
  158. bndPut("q1 = ", q);
  159. if (genRandBn(q, qbits, 0xFF, 1, seed, len) < 0)
  160. return -1;
  161. bndPut("q2 = ", q);
  162. /* And search for a prime */
  163. i = primeGen(q, (unsigned (*)(unsigned))0, f ? genProgress : 0,
  164. (void *)&progress, 0);
  165. bndPut("q = ", q);
  166. if (i < 0)
  167. return -1;
  168. /* ...and for p */
  169. (void)bnSetQ(p, 0);
  170. if (genRandBn(p, pbits, 0xC0, 1, seed, len) < 0)
  171. return -1;
  172. bndPut("p1 = ", p);
  173. /* Temporarily double q */
  174. if (bnLShift(q, 1) < 0)
  175. return -1;
  176. bnBegin(&h);
  177. bnBegin(&e);
  178. /* Set p = p - (p mod q) + 1, i.e. congruent to 1 mod 2*q */
  179. if (bnMod(&e, p, q) < 0)
  180. goto failed;
  181. if (bnSub(p, &e) < 0 || bnAddQ(p, 1) < 0)
  182. goto failed;
  183. bndPut("p2 = ", p);
  184. if (f)
  185. genProgress(&progress, ' ');
  186. /* And search for a prime */
  187. i = primeGenStrong(p, q, f ? genProgress : 0, (void *)&progress);
  188. if (i < 0)
  189. return -1;
  190. bndPut("p = ", p);
  191. /* Reduce q again */
  192. bnRShift(q, 1);
  193. /* Now hunt for a suitable g - first, find (p-1)/q */
  194. if (bnDivMod(&e, &h, p, q) < 0)
  195. goto failed;
  196. /* e is now the exponent (p-1)/q, and h is the remainder (one!) */
  197. if (bnBits(&h) != 1) {
  198. bndPut("Huh? p % q = ", &h);
  199. goto failed;
  200. }
  201. if (f)
  202. genProgress(&progress, ' ');
  203. /* Search for a suitable h */
  204. if (bnSetQ(&h, 2) < 0 || bnTwoExpMod(g, &e, p) < 0)
  205. goto failed;
  206. i++;
  207. while (bnBits(g) < 2) {
  208. if (f)
  209. genProgress(&progress, '.');
  210. if (bnAddQ(&h, 1) < 0 || bnExpMod(g, &h, &e, p) < 0)
  211. goto failed;
  212. i++;
  213. }
  214. if (f)
  215. genProgress(&progress, '*');
  216. #if CLOCK_AVAIL
  217. gettime(&stop);
  218. #endif
  219. /*
  220. * Now pick the secret, x. Choose it a bit larger than q and do
  221. * modular reduction to make it uniformly distributed.
  222. */
  223. bnSetQ(x, 0);
  224. /* XXX SECURITY ALERT Replace with a real RNG! SECURITY ALERT XXX */
  225. if (genRandBn(x, qbits+8, 0, 0, seed, len) < 0)
  226. goto failed;
  227. if (bnMod(x, x, q) < 0 || bnExpMod(y, g, x, p) < 0)
  228. goto failed;
  229. i++;
  230. if (f)
  231. putc('\n', f);
  232. printf("%d modular exponentiations performed.\n", i);
  233. #if CLOCK_AVAIL
  234. subtime(stop, start);
  235. s = sec(stop);
  236. bndPrintf("%u/%u-bit time = %lu.%03u sec.", pbits, qbits,
  237. s, msec(stop));
  238. if (s > 60) {
  239. putchar(' ');
  240. putchar('(');
  241. if (s > 3600)
  242. printf("%u:%02u", (unsigned)(s/3600),
  243. (unsigned)(s/60%60));
  244. else
  245. printf("%u", (unsigned)(s/60));
  246. printf(":%02u)", (unsigned)(s%60));
  247. }
  248. putchar('\n');
  249. #endif
  250. bndPut("q = ", q);
  251. bndPut("p = ", p);
  252. bndPut("h = ", &h);
  253. bndPut("g = ", g);
  254. bndPut("x = ", x);
  255. bndPut("y = ", y);
  256. bnEnd(&h);
  257. bnEnd(&e);
  258. return 0;
  259. failed:
  260. bnEnd(&h);
  261. bnEnd(&e);
  262. return -1;
  263. }
  264. static int
  265. dsaSign(struct BigNum const *p, struct BigNum const *q, struct BigNum const *g,
  266. struct BigNum const *x, struct BigNum const *y,
  267. struct BigNum const *hash, struct BigNum const *k,
  268. struct BigNum *r, struct BigNum *s)
  269. {
  270. int retval = -1;
  271. struct BigNum t;
  272. (void)y;
  273. bnBegin(&t);
  274. /* Make the signature... first the precomputation */
  275. /* Compute r = (g^k mod p) mod q */
  276. if (bnExpMod(r, g, k, p) < 0 || bnMod(r, r, q) < 0)
  277. goto failed;
  278. /* Compute s = k^-1 * (hash + x*r) mod q */
  279. if (bnInv(&t, k, q) < 0)
  280. goto failed;
  281. if (bnMul(s, x, r) < 0 || bnMod(s, s, q) < 0)
  282. goto failed;
  283. /* End of precomputation. Steps after this require the hash. */
  284. if (bnAdd(s, hash) < 0)
  285. goto failed;
  286. if (bnCmp(s, q) > 0 && bnSub(s, q) < 0)
  287. goto failed;
  288. if (bnMul(s, s, &t) < 0 || bnMod(s, s, q) < 0)
  289. goto failed;
  290. /* Okay, r and s are the signature! */
  291. retval = 0;
  292. failed:
  293. bnEnd(&t);
  294. return retval;
  295. }
  296. /* Faster version, using precomputed tables */
  297. static int
  298. dsaSignFast(struct BigNum const *p, struct BigNum const *q,
  299. struct BnBasePrecomp const *pre,
  300. struct BigNum const *x, struct BigNum const *y,
  301. struct BigNum const *hash, struct BigNum const *k,
  302. struct BigNum *r, struct BigNum *s)
  303. {
  304. int retval = -1;
  305. struct BigNum t;
  306. (void)y;
  307. bnBegin(&t);
  308. /* Make the signature... first the precomputation */
  309. /* Compute r = (g^k mod p) mod q */
  310. if (bnBasePrecompExpMod(r, pre, k, p) < 0 || bnMod(r, r, q) < 0)
  311. goto failed;
  312. /* Compute s = k^-1 * (hash + x*r) mod q */
  313. if (bnInv(&t, k, q) < 0)
  314. goto failed;
  315. if (bnMul(s, x, r) < 0 || bnMod(s, s, q) < 0)
  316. goto failed;
  317. /* End of precomputation. Steps after this require the hash. */
  318. if (bnAdd(s, hash) < 0)
  319. goto failed;
  320. if (bnCmp(s, q) > 0 && bnSub(s, q) < 0)
  321. goto failed;
  322. if (bnMul(s, s, &t) < 0 || bnMod(s, s, q) < 0)
  323. goto failed;
  324. /* Okay, r and s are the signature! */
  325. retval = 0;
  326. failed:
  327. bnEnd(&t);
  328. return retval;
  329. }
  330. /*
  331. * Returns 1 for a good signature, 0 for bad, and -1 on error.
  332. */
  333. static int
  334. dsaVerify(struct BigNum const *p, struct BigNum const *q,
  335. struct BigNum const *g, struct BigNum const *y,
  336. struct BigNum const *r, struct BigNum const *s,
  337. struct BigNum const *hash)
  338. {
  339. struct BigNum w, u1, u2;
  340. int retval = -1;
  341. bnBegin(&w);
  342. bnBegin(&u1);
  343. bnBegin(&u2);
  344. if (bnInv(&w, s, q) < 0)
  345. goto failed;
  346. if (bnMul(&u1, hash, &w) < 0 || bnMod(&u1, &u1, q) < 0)
  347. goto failed;
  348. if (bnMul(&u2, r, &w) < 0 || bnMod(&u2, &u2, q) < 0)
  349. goto failed;
  350. /* Now for the expensive part... */
  351. if (bnDoubleExpMod(&w, g, &u1, y, &u2, p) < 0)
  352. goto failed;
  353. if (bnMod(&w, &w, q) < 0)
  354. goto failed;
  355. retval = (bnCmp(r, &w) == 0);
  356. failed:
  357. bnEnd(&u2);
  358. bnEnd(&u1);
  359. bnEnd(&w);
  360. return retval;
  361. }
  362. #define divide_by_n(sec, msec, n) \
  363. ( msec += 1000 * (sec % n), \
  364. sec /= n, msec /= n, \
  365. sec += msec / 1000, \
  366. msec %= 1000 )
  367. static int
  368. dsaTest(struct BigNum const *p, struct BigNum const *q, struct BigNum const *g,
  369. struct BigNum const *x, struct BigNum const *y)
  370. {
  371. struct BigNum hash, r, s, k;
  372. struct BigNum r1, s1;
  373. struct BnBasePrecomp pre;
  374. unsigned bits;
  375. unsigned i;
  376. int verified;
  377. int retval = -1;
  378. unsigned char foo[4], bar[4];
  379. #if CLOCK_AVAIL
  380. timetype start, stop;
  381. unsigned long cursec, sigsec = 0, sig1sec = 0, versec = 0;
  382. unsigned curms, sigms = 0, sig1ms = 0, verms = 0;
  383. unsigned j, n, m = 0;
  384. #endif
  385. bnBegin(&hash);
  386. bnBegin(&r); bnBegin(&r1);
  387. bnBegin(&s); bnBegin(&s1);
  388. bnBegin(&k);
  389. bits = bnBits(q);
  390. strcpy((char *)foo, "foo");
  391. strcpy((char *)bar, "bar");
  392. /* Precompute powers of g */
  393. if (bnBasePrecompBegin(&pre, g, p, bits) < 0)
  394. goto failed;
  395. bndPrintf(" N\tSigning \tSigning1\tVerifying\tStatus\n");
  396. for (i = 0; i < 25; i++) {
  397. /* Pick a random hash, the right length. */
  398. (void)bnSetQ(&k, 0);
  399. if (genRandBn(&hash, bits, 0, 0, foo, 4) < 0)
  400. goto failed;
  401. /* Make the signature... */
  402. /*
  403. * XXX SECURITY ALERT XXX
  404. * XXX Replace with a real RNG! XXX
  405. * XXX SECURITY ALERT XXX
  406. */
  407. (void)bnSetQ(&k, 0);
  408. if (genRandBn(&k, bnBits(q)+8, 0, 0, bar, 4) < 0)
  409. goto failed;
  410. /* Reduce k to the correct range */
  411. if (bnMod(&k, &k, q) < 0)
  412. goto failed;
  413. #if CLOCK_AVAIL
  414. /* Decide on a number of iterations to perform... */
  415. m += n = i+1; /* This goes from 1 to 325 */
  416. bndPrintf("%3d", n);
  417. gettime(&start);
  418. for (j = 0; j < n; j++)
  419. #endif
  420. if (dsaSign(p, q, g, x, y, &hash, &k, &r, &s) < 0)
  421. goto failed;
  422. #if CLOCK_AVAIL
  423. gettime(&stop);
  424. subtime(stop, start);
  425. sigsec += cursec = sec(stop);
  426. sigms += curms = msec(stop);
  427. divide_by_n(cursec, curms, n);
  428. bndPrintf("\t%lu.%03u\t\t", cursec, curms);
  429. #else
  430. bndPrintf("\t*\t\t");
  431. #endif
  432. fflush(stdout);
  433. #if CLOCK_AVAIL
  434. gettime(&start);
  435. for (j = 0; j < n; j++)
  436. #endif
  437. if (dsaSignFast(p, q, &pre, x, y, &hash, &k, &r1, &s1) < 0)
  438. goto failed;
  439. #if CLOCK_AVAIL
  440. gettime(&stop);
  441. subtime(stop, start);
  442. sig1sec += cursec = sec(stop);
  443. sig1ms += curms = msec(stop);
  444. divide_by_n(cursec, curms, n);
  445. bndPrintf("%lu.%03u\t\t", cursec, curms);
  446. #else
  447. bndPrintf("*\t\t");
  448. #endif
  449. fflush(stdout);
  450. if (bnCmp(&r, &r1) != 0) {
  451. printf("\a** Error r != r1");
  452. bndPut("g = ", g);
  453. bndPut("k = ", &k);
  454. bndPut("r = ", &r);
  455. bndPut("r1= ", &r1);
  456. }
  457. if (bnCmp(&s, &s1) != 0) {
  458. printf("\a** Error r != r1");
  459. bndPut("g = ", g);
  460. bndPut("k = ", &k);
  461. bndPut("s = ", &s);
  462. bndPut("s1= ", &s1);
  463. }
  464. /* Okay, r and s are the signature! Now, verify it. */
  465. #if CLOCK_AVAIL
  466. gettime(&start);
  467. verified = 0; /* To silence warning */
  468. for (j = 0; j < n; j++) {
  469. #endif
  470. verified = dsaVerify(p, q, g, y, &r, &s, &hash);
  471. if (verified <= 0)
  472. break;
  473. }
  474. #if CLOCK_AVAIL
  475. gettime(&stop);
  476. subtime(stop, start);
  477. versec += cursec = sec(stop);
  478. verms += curms = msec(stop);
  479. divide_by_n(cursec, curms, j);
  480. bndPrintf("%lu.%03u\t\t", cursec, curms);
  481. #else
  482. bndPrintf("*\t\t");
  483. #endif
  484. if (verified > 0) {
  485. printf("Test successful.\n");
  486. } else if (verified == 0) {
  487. printf("\aSignature did NOT check!.\n");
  488. bndPut("hash = ", &hash);
  489. bndPut("k = ", &k);
  490. bndPut("r = ", &r);
  491. bndPut("s = ", &s);
  492. getchar();
  493. } else {
  494. printf("\a** Error while verifying");
  495. bndPut("hash = ", &hash);
  496. bndPut("k = ", &k);
  497. bndPut("r = ", &r);
  498. bndPut("s = ", &s);
  499. getchar();
  500. goto failed;
  501. }
  502. }
  503. #if CLOCK_AVAIL
  504. divide_by_n(sigsec, sigms, m);
  505. divide_by_n(sig1sec, sig1ms, m);
  506. divide_by_n(versec, verms, m);
  507. bndPrintf("%3u\t%lu.%03u\t\t%lu.%03u\t\t%lu.%03u\t\tAVERAGE %u/%u\n",
  508. m, sigsec, sigms, sig1sec, sig1ms, versec, verms,
  509. bnBits(p), bnBits(q));
  510. #endif
  511. /* Success */
  512. retval = 0;
  513. failed:
  514. bnBasePrecompEnd(&pre);
  515. bnEnd(&k);
  516. bnEnd(&s1); bnEnd(&s);
  517. bnEnd(&r1); bnEnd(&r);
  518. bnEnd(&hash);
  519. return retval;
  520. }
  521. /* Copy the command line to the buffer. */
  522. static unsigned
  523. copy(unsigned char *buf, int argc, char **argv)
  524. {
  525. unsigned pos, len;
  526. pos = 0;
  527. while (--argc) {
  528. len = strlen(*++argv);
  529. memcpy(buf, *argv, len);
  530. buf += len;
  531. pos += len;
  532. if (argc > 1) {
  533. *buf++ = ' ';
  534. pos++;
  535. }
  536. }
  537. return pos;
  538. }
  539. int
  540. main(int argc, char **argv)
  541. {
  542. unsigned len;
  543. struct BigNum p, q, g, x, y;
  544. unsigned char buf[1024];
  545. if (argc < 2) {
  546. fprintf(stderr, "Usage: %s <seed>\n", argv[0]);
  547. fputs("\
  548. <seed> should be a a string of bytes to be hashed to seed the prime\n\
  549. generator. Note that unquoted whitespace between words will be counted\n\
  550. as a single space. To include multiple spaces, quote them.\n", stderr);
  551. return 1;
  552. }
  553. bnInit();
  554. bnBegin(&p);
  555. bnBegin(&q);
  556. bnBegin(&g);
  557. bnBegin(&x);
  558. bnBegin(&y);
  559. len = copy(buf, argc, argv);
  560. dsaGen(&p, 512, &q, 160, &g, &x, &y, buf, len, stdout);
  561. dsaTest(&p, &q, &g, &x, &y);
  562. len = copy(buf, argc, argv);
  563. dsaGen(&p, 768, &q, 160, &g, &x, &y, buf, len, stdout);
  564. dsaTest(&p, &q, &g, &x, &y);
  565. len = copy(buf, argc, argv);
  566. dsaGen(&p, 1024, &q, 160, &g, &x, &y, buf, len, stdout);
  567. dsaTest(&p, &q, &g, &x, &y);
  568. len = copy(buf, argc, argv);
  569. dsaGen(&p, 1536, &q, 192, &g, &x, &y, buf, len, stdout);
  570. dsaTest(&p, &q, &g, &x, &y);
  571. len = copy(buf, argc, argv);
  572. dsaGen(&p, 2048, &q, 224, &g, &x, &y, buf, len, stdout);
  573. dsaTest(&p, &q, &g, &x, &y);
  574. len = copy(buf, argc, argv);
  575. dsaGen(&p, 3072, &q, 256, &g, &x, &y, buf, len, stdout);
  576. dsaTest(&p, &q, &g, &x, &y);
  577. len = copy(buf, argc, argv);
  578. dsaGen(&p, 4096, &q, 288, &g, &x, &y, buf, len, stdout);
  579. dsaTest(&p, &q, &g, &x, &y);
  580. bnEnd(&y);
  581. bnEnd(&x);
  582. bnEnd(&g);
  583. bnEnd(&q);
  584. bnEnd(&p);
  585. return 0;
  586. }