dsa_generate_pqg.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. /* LibTomCrypt, modular cryptographic library -- Tom St Denis
  2. *
  3. * LibTomCrypt is a library that provides various cryptographic
  4. * algorithms in a highly modular and flexible manner.
  5. *
  6. * The library is free for all purposes without any express
  7. * guarantee it works.
  8. */
  9. #include "tomcrypt.h"
  10. /**
  11. @file dsa_generate_pqg.c
  12. DSA implementation - generate DSA parameters p, q & g
  13. */
  14. #ifdef LTC_MDSA
  15. /**
  16. Create DSA parameters (INTERNAL ONLY, not part of public API)
  17. @param prng An active PRNG state
  18. @param wprng The index of the PRNG desired
  19. @param group_size Size of the multiplicative group (octets)
  20. @param modulus_size Size of the modulus (octets)
  21. @param p [out] bignum where generated 'p' is stored (must be initialized by caller)
  22. @param q [out] bignum where generated 'q' is stored (must be initialized by caller)
  23. @param g [out] bignum where generated 'g' is stored (must be initialized by caller)
  24. @return CRYPT_OK if successful, upon error this function will free all allocated memory
  25. */
  26. static int _dsa_make_params(prng_state *prng, int wprng, int group_size, int modulus_size, void *p, void *q, void *g)
  27. {
  28. unsigned long L, N, n, outbytes, seedbytes, counter, j, i;
  29. int err, res, mr_tests_q, mr_tests_p, found_p, found_q, hash;
  30. unsigned char *wbuf, *sbuf, digest[MAXBLOCKSIZE];
  31. void *t2L1, *t2N1, *t2q, *t2seedlen, *U, *W, *X, *c, *h, *e, *seedinc;
  32. /* check size */
  33. if (group_size >= LTC_MDSA_MAX_GROUP || group_size < 1 || group_size >= modulus_size) {
  34. return CRYPT_INVALID_ARG;
  35. }
  36. /* FIPS-186-4 A.1.1.2 Generation of the Probable Primes p and q Using an Approved Hash Function
  37. *
  38. * L = The desired length of the prime p (in bits e.g. L = 1024)
  39. * N = The desired length of the prime q (in bits e.g. N = 160)
  40. * seedlen = The desired bit length of the domain parameter seed; seedlen shallbe equal to or greater than N
  41. * outlen = The bit length of Hash function
  42. *
  43. * 1. Check that the (L, N)
  44. * 2. If (seedlen <N), then return INVALID.
  45. * 3. n = ceil(L / outlen) - 1
  46. * 4. b = L- 1 - (n * outlen)
  47. * 5. domain_parameter_seed = an arbitrary sequence of seedlen bits
  48. * 6. U = Hash (domain_parameter_seed) mod 2^(N-1)
  49. * 7. q = 2^(N-1) + U + 1 - (U mod 2)
  50. * 8. Test whether or not q is prime as specified in Appendix C.3
  51. * 9. If qis not a prime, then go to step 5.
  52. * 10. offset = 1
  53. * 11. For counter = 0 to (4L- 1) do {
  54. * For j=0 to n do {
  55. * Vj = Hash ((domain_parameter_seed+ offset + j) mod 2^seedlen
  56. * }
  57. * W = V0 + (V1 *2^outlen) + ... + (Vn-1 * 2^((n-1) * outlen)) + ((Vn mod 2^b) * 2^(n * outlen))
  58. * X = W + 2^(L-1) Comment: 0 <= W < 2^(L-1); hence 2^(L-1) <= X < 2^L
  59. * c = X mod 2*q
  60. * p = X - (c - 1) Comment: p ~ 1 (mod 2*q)
  61. * If (p >= 2^(L-1)) {
  62. * Test whether or not p is prime as specified in Appendix C.3.
  63. * If p is determined to be prime, then return VALID and the values of p, qand (optionally) the values of domain_parameter_seed and counter
  64. * }
  65. * offset = offset + n + 1 Comment: Increment offset
  66. * }
  67. */
  68. seedbytes = group_size;
  69. L = modulus_size * 8;
  70. N = group_size * 8;
  71. /* XXX-TODO no Lucas test */
  72. #ifdef LTC_MPI_HAS_LUCAS_TEST
  73. /* M-R tests (when followed by one Lucas test) according FIPS-186-4 - Appendix C.3 - table C.1 */
  74. mr_tests_p = (L <= 2048) ? 3 : 2;
  75. if (N <= 160) { mr_tests_q = 19; }
  76. else if (N <= 224) { mr_tests_q = 24; }
  77. else { mr_tests_q = 27; }
  78. #else
  79. /* M-R tests (without Lucas test) according FIPS-186-4 - Appendix C.3 - table C.1 */
  80. if (L <= 1024) { mr_tests_p = 40; }
  81. else if (L <= 2048) { mr_tests_p = 56; }
  82. else { mr_tests_p = 64; }
  83. if (N <= 160) { mr_tests_q = 40; }
  84. else if (N <= 224) { mr_tests_q = 56; }
  85. else { mr_tests_q = 64; }
  86. #endif
  87. if (N <= 256) {
  88. hash = register_hash(&sha256_desc);
  89. }
  90. else if (N <= 384) {
  91. hash = register_hash(&sha384_desc);
  92. }
  93. else if (N <= 512) {
  94. hash = register_hash(&sha512_desc);
  95. }
  96. else {
  97. return CRYPT_INVALID_ARG; /* group_size too big */
  98. }
  99. if ((err = hash_is_valid(hash)) != CRYPT_OK) { return err; }
  100. outbytes = hash_descriptor[hash].hashsize;
  101. n = ((L + outbytes*8 - 1) / (outbytes*8)) - 1;
  102. if ((wbuf = XMALLOC((n+1)*outbytes)) == NULL) { err = CRYPT_MEM; goto cleanup3; }
  103. if ((sbuf = XMALLOC(seedbytes)) == NULL) { err = CRYPT_MEM; goto cleanup2; }
  104. err = mp_init_multi(&t2L1, &t2N1, &t2q, &t2seedlen, &U, &W, &X, &c, &h, &e, &seedinc, NULL);
  105. if (err != CRYPT_OK) { goto cleanup1; }
  106. if ((err = mp_2expt(t2L1, L-1)) != CRYPT_OK) { goto cleanup; }
  107. /* t2L1 = 2^(L-1) */
  108. if ((err = mp_2expt(t2N1, N-1)) != CRYPT_OK) { goto cleanup; }
  109. /* t2N1 = 2^(N-1) */
  110. if ((err = mp_2expt(t2seedlen, seedbytes*8)) != CRYPT_OK) { goto cleanup; }
  111. /* t2seedlen = 2^seedlen */
  112. for(found_p=0; !found_p;) {
  113. /* q */
  114. for(found_q=0; !found_q;) {
  115. if (prng_descriptor[wprng].read(sbuf, seedbytes, prng) != seedbytes) { err = CRYPT_ERROR_READPRNG; goto cleanup; }
  116. i = outbytes;
  117. if ((err = hash_memory(hash, sbuf, seedbytes, digest, &i)) != CRYPT_OK) { goto cleanup; }
  118. if ((err = mp_read_unsigned_bin(U, digest, outbytes)) != CRYPT_OK) { goto cleanup; }
  119. if ((err = mp_mod(U, t2N1, U)) != CRYPT_OK) { goto cleanup; }
  120. if ((err = mp_add(t2N1, U, q)) != CRYPT_OK) { goto cleanup; }
  121. if (!mp_isodd(q)) mp_add_d(q, 1, q);
  122. if ((err = mp_prime_is_prime(q, mr_tests_q, &res)) != CRYPT_OK) { goto cleanup; }
  123. if (res == LTC_MP_YES) found_q = 1;
  124. }
  125. /* p */
  126. if ((err = mp_read_unsigned_bin(seedinc, sbuf, seedbytes)) != CRYPT_OK) { goto cleanup; }
  127. if ((err = mp_add(q, q, t2q)) != CRYPT_OK) { goto cleanup; }
  128. for(counter=0; counter < 4*L && !found_p; counter++) {
  129. for(j=0; j<=n; j++) {
  130. if ((err = mp_add_d(seedinc, 1, seedinc)) != CRYPT_OK) { goto cleanup; }
  131. if ((err = mp_mod(seedinc, t2seedlen, seedinc)) != CRYPT_OK) { goto cleanup; }
  132. /* seedinc = (seedinc+1) % 2^seed_bitlen */
  133. if ((i = mp_unsigned_bin_size(seedinc)) > seedbytes) { err = CRYPT_INVALID_ARG; goto cleanup; }
  134. zeromem(sbuf, seedbytes);
  135. if ((err = mp_to_unsigned_bin(seedinc, sbuf + seedbytes-i)) != CRYPT_OK) { goto cleanup; }
  136. i = outbytes;
  137. err = hash_memory(hash, sbuf, seedbytes, wbuf+(n-j)*outbytes, &i);
  138. if (err != CRYPT_OK) { goto cleanup; }
  139. }
  140. if ((err = mp_read_unsigned_bin(W, wbuf, (n+1)*outbytes)) != CRYPT_OK) { goto cleanup; }
  141. if ((err = mp_mod(W, t2L1, W)) != CRYPT_OK) { goto cleanup; }
  142. if ((err = mp_add(W, t2L1, X)) != CRYPT_OK) { goto cleanup; }
  143. if ((err = mp_mod(X, t2q, c)) != CRYPT_OK) { goto cleanup; }
  144. if ((err = mp_sub_d(c, 1, p)) != CRYPT_OK) { goto cleanup; }
  145. if ((err = mp_sub(X, p, p)) != CRYPT_OK) { goto cleanup; }
  146. if (mp_cmp(p, t2L1) != LTC_MP_LT) {
  147. /* p >= 2^(L-1) */
  148. if ((err = mp_prime_is_prime(p, mr_tests_p, &res)) != CRYPT_OK) { goto cleanup; }
  149. if (res == LTC_MP_YES) {
  150. found_p = 1;
  151. }
  152. }
  153. }
  154. }
  155. /* FIPS-186-4 A.2.1 Unverifiable Generation of the Generator g
  156. * 1. e = (p - 1)/q
  157. * 2. h = any integer satisfying: 1 < h < (p - 1)
  158. * h could be obtained from a random number generator or from a counter that changes after each use
  159. * 3. g = h^e mod p
  160. * 4. if (g == 1), then go to step 2.
  161. *
  162. */
  163. if ((err = mp_sub_d(p, 1, e)) != CRYPT_OK) { goto cleanup; }
  164. if ((err = mp_div(e, q, e, c)) != CRYPT_OK) { goto cleanup; }
  165. /* e = (p - 1)/q */
  166. i = mp_count_bits(p);
  167. do {
  168. do {
  169. if ((err = rand_bn_bits(h, i, prng, wprng)) != CRYPT_OK) { goto cleanup; }
  170. } while (mp_cmp(h, p) != LTC_MP_LT || mp_cmp_d(h, 2) != LTC_MP_GT);
  171. if ((err = mp_sub_d(h, 1, h)) != CRYPT_OK) { goto cleanup; }
  172. /* h is randon and 1 < h < (p-1) */
  173. if ((err = mp_exptmod(h, e, p, g)) != CRYPT_OK) { goto cleanup; }
  174. } while (mp_cmp_d(g, 1) == LTC_MP_EQ);
  175. err = CRYPT_OK;
  176. cleanup:
  177. mp_clear_multi(t2L1, t2N1, t2q, t2seedlen, U, W, X, c, h, e, seedinc, NULL);
  178. cleanup1:
  179. XFREE(sbuf);
  180. cleanup2:
  181. XFREE(wbuf);
  182. cleanup3:
  183. return err;
  184. }
  185. /**
  186. Generate DSA parameters p, q & g
  187. @param prng An active PRNG state
  188. @param wprng The index of the PRNG desired
  189. @param group_size Size of the multiplicative group (octets)
  190. @param modulus_size Size of the modulus (octets)
  191. @param key [out] Where to store the created key
  192. @return CRYPT_OK if successful.
  193. */
  194. int dsa_generate_pqg(prng_state *prng, int wprng, int group_size, int modulus_size, dsa_key *key)
  195. {
  196. int err;
  197. LTC_ARGCHK(key != NULL);
  198. LTC_ARGCHK(ltc_mp.name != NULL);
  199. /* init mp_ints */
  200. if ((err = mp_init_multi(&key->p, &key->g, &key->q, &key->x, &key->y, NULL)) != CRYPT_OK) {
  201. return err;
  202. }
  203. /* generate params */
  204. err = _dsa_make_params(prng, wprng, group_size, modulus_size, key->p, key->q, key->g);
  205. if (err != CRYPT_OK) {
  206. goto cleanup;
  207. }
  208. key->qord = group_size;
  209. return CRYPT_OK;
  210. cleanup:
  211. dsa_free(key);
  212. return err;
  213. }
  214. #endif
  215. /* ref: $Format:%D$ */
  216. /* git commit: $Format:%H$ */
  217. /* commit time: $Format:%ai$ */