keygen.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. /*
  2. * Copyright (c) 1995 Colin Plumb. All rights reserved.
  3. * For licensing and other legal details, see the file legal.c.
  4. *
  5. * keygen.c - generate RSA key pairs using the bignum library.
  6. */
  7. #include "first.h"
  8. #include <assert.h>
  9. #include <stdio.h> /* For FILE type */
  10. #include <string.h> /* For memset */
  11. #include "bn.h"
  12. #include "prime.h"
  13. #include "keygen.h"
  14. #include "keys.h" /* Key structures */
  15. #include "random.h" /* Good random number generator */
  16. #if BNDEBUG
  17. #include "bnprint.h"
  18. #define bndPut(prompt, bn) bnPrint(stdout, prompt, bn, "\n")
  19. #define bndPrintf printf
  20. #else
  21. #define bndPut(prompt, bn) ((void)(prompt),(void)(bn))
  22. #define bndPrintf (void)
  23. #endif
  24. #include "kludge.h"
  25. /*
  26. * Generate a random bignum of a specified length, with the given
  27. * high and low 8 bits. "High" is merged into the high 8 bits of the
  28. * number. For example, set it to 0x80 to ensure that the number is
  29. * exactly "bits" bits long (i.e. 2^(bits-1) <= bn < 2^bits).
  30. * "Low" is merged into the low 8 bits. For example, set it to
  31. * 1 to ensure that you generate an odd number.
  32. */
  33. static int
  34. genRandBn(struct BigNum *bn, unsigned bits, byte high, byte low)
  35. {
  36. unsigned char buf[64];
  37. unsigned bytes;
  38. unsigned l;
  39. int err;
  40. bnSetQ(bn, 0);
  41. bytes = (bits+7) / 8;
  42. l = bytes < sizeof(buf) ? bytes : sizeof(buf);
  43. randBytes(buf, l);
  44. /* Mask off excess high bits */
  45. buf[0] &= 255 >> (-bits & 7);
  46. /* Merge in specified high bits */
  47. buf[0] |= high >> (-bits & 7);
  48. if (bits & 7)
  49. buf[1] |= high << (bits & 7);
  50. for (;;) {
  51. bytes -= l;
  52. if (!bytes) /* Last word - merge in low bits */
  53. buf[l-1] |= low;
  54. err = bnInsertBigBytes(bn, buf, bytes, l);
  55. if (!bytes || err < 0)
  56. break;
  57. l = bytes < sizeof(buf) ? bytes : sizeof(buf);
  58. randBytes(buf, l);
  59. }
  60. memset(buf, 0, sizeof(buf));
  61. return err;
  62. }
  63. /*
  64. * Generate a new RSA key, with the specified number of bits and
  65. * public exponent. The high two bits of each prime are always
  66. * set to make the number more difficult to factor by forcing the
  67. * number into the high end of the range.
  68. */
  69. struct Progress {
  70. FILE *f;
  71. unsigned column;
  72. unsigned wrap;
  73. };
  74. static int
  75. genProgress(void *arg, int c)
  76. {
  77. struct Progress *p = arg;
  78. if (++p->column > p->wrap) {
  79. putc('\n', p->f);
  80. p->column = 1;
  81. }
  82. putc(c, p->f);
  83. fflush(p->f);
  84. return 0;
  85. }
  86. int
  87. genRsaKey(struct PubKey *pub, struct SecKey *sec,
  88. unsigned bits, unsigned exp, FILE *file)
  89. {
  90. int modexps = 0;
  91. struct BigNum t; /* Temporary */
  92. int i;
  93. struct Progress progress;
  94. progress.f = file;
  95. progress.column = 0;
  96. progress.wrap = 78;
  97. if (bnSetQ(&pub->e, exp))
  98. return -1;
  99. /* Find p - choose a starting place */
  100. if (genRandBn(&sec->p, bits/2, 0xC0, 1) < 0)
  101. return -1;
  102. /* And search for a prime */
  103. i = primeGen(&sec->p, randRange, file ? genProgress : 0, &progress,
  104. exp, 0);
  105. if (i < 0)
  106. goto error;
  107. modexps = i;
  108. assert(bnModQ(&sec->p, exp) != 1);
  109. bndPut("p = ", &sec->p);
  110. do {
  111. /* Visual separator between the two progress indicators */
  112. if (file)
  113. genProgress(&progress, ' ');
  114. if (genRandBn(&sec->q, (bits+1)/2, 0xC0, 1) < 0)
  115. goto error;
  116. if (bnCopy(&pub->n, &sec->q) < 0)
  117. goto error;
  118. if (bnSub(&pub->n, &sec->p) < 0)
  119. goto error;
  120. /* Note that bnSub(a,b) returns abs(a-b) */
  121. } while (bnBits(&pub->n) < bits/2-5);
  122. if (file)
  123. fflush(file); /* Ensure the separators are visible */
  124. i = primeGen(&sec->q, randRange, file ? genProgress : 0, &progress,
  125. exp, 0);
  126. if (i < 0)
  127. goto error;
  128. modexps += i;
  129. assert(bnModQ(&sec->p, exp) != 1);
  130. bndPut("q = ", &sec->q);
  131. /* Wash the random number pool. */
  132. randFlush();
  133. /* Ensure that q is larger */
  134. if (bnCmp(&sec->p, &sec->q) > 0)
  135. bnSwap(&sec->p, &sec->q);
  136. bndPut("p = ", &sec->p);
  137. bndPut("q = ", &sec->q);
  138. /*
  139. * Now we dive into a large amount of fiddling to compute d,
  140. * the decryption exponent, from the encryption exponent.
  141. * We require that e*d == 1 (mod p-1) and e*d == 1 (mod q-1).
  142. * This can alomost be done via the Chinese Remainder Algorithm,
  143. * but it doesn't quite apply, because p-1 and q-1 are not
  144. * realitvely prime. Our task is to massage these into
  145. * two numbers a and b such that a*b = lcm(p-1,q-1) and
  146. * gcd(a,b) = 1. The technique is not well documented,
  147. * so I'll describe it here.
  148. * First, let d = gcd(p-1,q-1), then let a' = (p-1)/d and
  149. * b' = (q-1)/d. By the definition of the gcd, gcd(a',b') at
  150. * this point is 1, but a'*b' is a factor of d shy of the desired
  151. * value. We have to produce a = a' * d1 and b = b' * d2 such
  152. * d1*d2 = d and gcd(a,b) is 1. This will be the case iff
  153. * gcd(a,d2) = gcd(b,d1) = 1. Since GCD is associative and
  154. * (gcd(x,y,z) = gcd(x,gcd(y,z)) = gcd(gcd(x,y),z), etc.),
  155. * gcd(a',b') = 1 implies that gcd(a',b',d) = 1 which implies
  156. * that gcd(a',gcd(b',d)) = gcd(gcd(a',d),b') = 1. So you can
  157. * extract gcd(b',d) from d and make it part of d2, and the
  158. * same for d1. And iterate? A pessimal example is x = 2*6^k
  159. * and y = 3*6^k. gcd(x,y) = 6^k and we have to divvy it up
  160. * somehow so that all the factors of 2 go to x and all the
  161. * factors of 3 go to y, ending up with a = 2*2^k and b = 3*3^k.
  162. *
  163. * Aah, fuck it. It's simpler to do one big inverse for now.
  164. * Later I'll figure out how to get this to work properly.
  165. */
  166. /* Decrement q temporarily */
  167. (void)bnSubQ(&sec->q, 1);
  168. /* And u = p-1, to be divided by gcd(p-1,q-1) */
  169. if (bnCopy(&sec->u, &sec->p) < 0)
  170. goto error;
  171. (void)bnSubQ(&sec->u, 1);
  172. bndPut("p-1 = ", &sec->u);
  173. bndPut("q-1 = ", &sec->q);
  174. /* Use t to store gcd(p-1,q-1) */
  175. bnBegin(&t);
  176. if (bnGcd(&t, &sec->q, &sec->u) < 0) {
  177. bnEnd(&t);
  178. goto error;
  179. }
  180. bndPut("t = gcd(p-1,q-1) = ", &t);
  181. /* Let d = (p-1) / gcd(p-1,q-1) (n is scratch for the remainder) */
  182. i = bnDivMod(&sec->d, &pub->n, &sec->u, &t);
  183. bndPut("(p-1)/t = ", &sec->d);
  184. bndPut("(p-1)%t = ", &pub->n);
  185. bnEnd(&t);
  186. if (i < 0)
  187. goto error;
  188. assert(bnBits(&pub->n) == 0);
  189. /* Now we have q-1 and d = (p-1) / gcd(p-1,q-1) */
  190. /* Find the product, n = lcm(p-1,q-1) = c * d */
  191. if (bnMul(&pub->n, &sec->q, &sec->d) < 0)
  192. goto error;
  193. bndPut("(p-1)*(q-1)/t = ", &pub->n);
  194. /* Find the inverse of the exponent mod n */
  195. i = bnInv(&sec->d, &pub->e, &pub->n);
  196. bndPut("e = ", &pub->e);
  197. bndPut("d = ", &sec->d);
  198. if (i < 0)
  199. goto error;
  200. assert(!i); /* We should NOT get an error here */
  201. /*
  202. * Now we have the comparatively simple task of computing
  203. * u = p^-1 mod q.
  204. */
  205. #if BNDEBUG
  206. bnMul(&sec->u, &sec->d, &pub->e);
  207. bndPut("d * e = ", &sec->u);
  208. bnMod(&pub->n, &sec->u, &sec->q);
  209. bndPut("d * e = ", &sec->u);
  210. bndPut("q-1 = ", &sec->q);
  211. bndPut("d * e % (q-1)= ", &pub->n);
  212. bnNorm(&pub->n);
  213. bnSubQ(&sec->p, 1);
  214. bndPut("d * e = ", &sec->u);
  215. bnMod(&sec->u, &sec->u, &sec->p);
  216. bndPut("p-1 = ", &sec->p);
  217. bndPut("d * e % (p-1)= ", &sec->u);
  218. bnNorm(&sec->u);
  219. bnAddQ(&sec->p, 1);
  220. #endif
  221. /* But it *would* be nice to have q back first. */
  222. (void)bnAddQ(&sec->q, 1);
  223. bndPut("p = ", &sec->p);
  224. bndPut("q = ", &sec->q);
  225. /* Now compute u = p^-1 mod q */
  226. i = bnInv(&sec->u, &sec->p, &sec->q);
  227. if (i < 0)
  228. goto error;
  229. bndPut("u = p^-1 % q = ", &sec->u);
  230. assert(!i); /* p and q had better be relatively prime! */
  231. #if BNDEBUG
  232. bnMul(&pub->n, &sec->u, &sec->p);
  233. bndPut("u * p = ", &pub->n);
  234. bnMod(&pub->n, &pub->n, &sec->q);
  235. bndPut("u * p % q = ", &pub->n);
  236. bnNorm(&pub->n);
  237. #endif
  238. /* And finally, n = p * q */
  239. if (bnMul(&pub->n, &sec->p, &sec->q) < 0)
  240. goto error;
  241. bndPut("n = p * q = ", &pub->n);
  242. /* And that's it... success! */
  243. if (file)
  244. putc('\n', file); /* Signal done */
  245. return modexps;
  246. error:
  247. if (file)
  248. fputs("?\n", file); /* Signal error */
  249. return -1;
  250. }
  251. /*
  252. * Chinese Remainder Theorem refresher.
  253. * The theorem is actually that, "given x mod a, x mod b, x mod c, x mod d,
  254. * etc., the value of x mod lcm(a, b, c, d, ...) is uniquely determined",
  255. * But everyone seems to use the name "theorem" to refer to the algorithm
  256. * to put the number back together.
  257. *
  258. * Doing it for multiple numbers efficiently is a bit hairier, so I'll
  259. * just consider it for two moduli, a and b. We assume that the inputs
  260. * are in the canonical equivalence class (0 <= xa = x mod a < a, and
  261. * 0 <= xb = x mod b < b), and we want the output in the same form.
  262. *
  263. * First, divide one or the other by gcd(a,b) to reduce the problem to
  264. * one of relatively prime numbers. You'll have to reduce the corresponding
  265. * xa or xb modulo the new modulus.
  266. *
  267. * Then, note that if xa == x (mod a), then x = xa + a*k. The problem
  268. * lies in finding k so that xa + a*k == xb (mod b). Rearranging
  269. * gives a*k == xb - xa (mod b), and then multiplying both sides by
  270. * a^-1, the inverse of a mod b, gives k == a^-1 * (xb-xa) (mod b).
  271. * If k is reduced mod b, then xa + a*k <= (a-1) + a * (b-1) =
  272. * a + a*(b-1) - 1 = a*b - 1, which is exactly as it should be to
  273. * be reduced mod a*b. And if all the inputs are >= 0, the output
  274. * will be non-negative.
  275. *
  276. * For multiple numbers, you can get the number into a similar mixed-
  277. * radix form x = xa + a*(k1 + b*(k2 + c*(k3 +...))). All the math
  278. * to do this is modulo the small numbers (and thus faster); only the
  279. * final summing has to be performed at large sizes. For the greatest
  280. * efficiency, order the numbers so a > b > c >..., so as many computations
  281. * as possible are small.
  282. *
  283. * So the total procedure for two numbers is:
  284. * - Let a be the larger and b be the smaller of the numbers.
  285. * - Divide b by gcd(a,b) to make it even smaller.
  286. * - Find a^-1 mod b.
  287. * - Find (xb-xa) mod b.
  288. * - Multiply (xb-xa) by a^-1, modulo b.
  289. * - Multiply that by a, without any modular reduction
  290. * - Add xa.
  291. */
  292. #if 0
  293. /* A simple test driver */
  294. #include "bnprint.h"
  295. #include <time.h>
  296. int
  297. main(void)
  298. {
  299. struct BigNum p, q, d, u;
  300. int i;
  301. clock_t interval;
  302. static unsigned const sizetable[] = {
  303. 384, 512, 513, 514, 515, 768, 1024, 1536, 2048, 0
  304. };
  305. unsigned const *sizeptr = sizetable;
  306. bnInit();
  307. bnRandSeed(1);
  308. bnBegin(&p);
  309. bnBegin(&q);
  310. bnBegin(&d);
  311. bnBegin(&u);
  312. while (*sizeptr) {
  313. printf("Generating a %u-bit RSA key\n", *sizeptr);
  314. interval = clock();
  315. i = genRsaKey(&p, &q, &d, &u, *sizeptr, 17, stdout);
  316. interval = clock() - interval;
  317. printf("genRsaKey returned %d. %ld.%06ld s\n", i,
  318. interval / 1000000, interval % 1000000);
  319. fputs("p = ", stdout);
  320. bnPrint(stdout, &p);
  321. fputs("\nq = ", stdout);
  322. bnPrint(stdout, &q);
  323. fputs("\nd = ", stdout);
  324. bnPrint(stdout, &d);
  325. fputs("\nu = ", stdout);
  326. bnPrint(stdout, &u);
  327. putchar('\n');
  328. sizeptr++;
  329. }
  330. bnEnd(&p);
  331. bnEnd(&q);
  332. bnEnd(&d);
  333. bnEnd(&u);
  334. return 0;
  335. }
  336. #endif