1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 #include "tomcrypt_private.h"
4
5 /**
6 @file dsa_generate_pqg.c
7 DSA implementation - generate DSA parameters p, q & g
8 */
9
10 #ifdef LTC_MDSA
11
12 /**
13 Create DSA parameters (INTERNAL ONLY, not part of public API)
14 @param prng An active PRNG state
15 @param wprng The index of the PRNG desired
16 @param group_size Size of the multiplicative group (octets)
17 @param modulus_size Size of the modulus (octets)
18 @param p [out] bignum where generated 'p' is stored (must be initialized by caller)
19 @param q [out] bignum where generated 'q' is stored (must be initialized by caller)
20 @param g [out] bignum where generated 'g' is stored (must be initialized by caller)
21 @return CRYPT_OK if successful, upon error this function will free all allocated memory
22 */
s_dsa_make_params(prng_state * prng,int wprng,int group_size,int modulus_size,void * p,void * q,void * g)23 static int s_dsa_make_params(prng_state *prng, int wprng, int group_size, int modulus_size, void *p, void *q, void *g)
24 {
25 unsigned long L, N, n, outbytes, seedbytes, counter, j, i;
26 int err, res, mr_tests_q, mr_tests_p, found_p, found_q, hash;
27 unsigned char *wbuf, *sbuf, digest[MAXBLOCKSIZE];
28 void *t2L1, *t2N1, *t2q, *t2seedlen, *U, *W, *X, *c, *h, *e, *seedinc;
29 const char *accepted_hashes[] = { "sha3-512", "sha512", "sha3-384", "sha384", "sha3-256", "sha256" };
30
31 /* check size */
32 if (group_size > LTC_MDSA_MAX_GROUP || group_size < 1 || group_size >= modulus_size || modulus_size > LTC_MDSA_MAX_MODULUS) {
33 return CRYPT_INVALID_ARG;
34 }
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
69 seedbytes = group_size;
70 L = (unsigned long)modulus_size * 8;
71 N = (unsigned long)group_size * 8;
72
73 /* XXX-TODO no Lucas test */
74 #ifdef LTC_MPI_HAS_LUCAS_TEST
75 /* M-R tests (when followed by one Lucas test) according FIPS-186-4 - Appendix C.3 - table C.1 */
76 mr_tests_p = (L <= 2048) ? 3 : 2;
77 if (N <= 160) { mr_tests_q = 19; }
78 else if (N <= 224) { mr_tests_q = 24; }
79 else { mr_tests_q = 27; }
80 #else
81 /* M-R tests (without Lucas test) according FIPS-186-4 - Appendix C.3 - table C.1 */
82 if (L <= 1024) { mr_tests_p = 40; }
83 else if (L <= 2048) { mr_tests_p = 56; }
84 else { mr_tests_p = 64; }
85
86 if (N <= 160) { mr_tests_q = 40; }
87 else if (N <= 224) { mr_tests_q = 56; }
88 else { mr_tests_q = 64; }
89 #endif
90
91 hash = -1;
92 for (i = 0; i < sizeof(accepted_hashes)/sizeof(accepted_hashes[0]); ++i) {
93 hash = find_hash(accepted_hashes[i]);
94 if (hash != -1) break;
95 }
96 if (hash == -1) {
97 return CRYPT_INVALID_ARG; /* no appropriate hash function found */
98 }
99 if (N > hash_descriptor[hash]->hashsize * 8) {
100 return CRYPT_INVALID_ARG; /* group_size too big */
101 }
102
103 if ((err = hash_is_valid(hash)) != CRYPT_OK) { return err; }
104 outbytes = hash_descriptor[hash]->hashsize;
105
106 n = ((L + outbytes*8 - 1) / (outbytes*8)) - 1;
107
108 if ((wbuf = XMALLOC((n+1)*outbytes)) == NULL) { err = CRYPT_MEM; goto cleanup3; }
109 if ((sbuf = XMALLOC(seedbytes)) == NULL) { err = CRYPT_MEM; goto cleanup2; }
110
111 err = mp_init_multi(&t2L1, &t2N1, &t2q, &t2seedlen, &U, &W, &X, &c, &h, &e, &seedinc, LTC_NULL);
112 if (err != CRYPT_OK) { goto cleanup1; }
113
114 if ((err = mp_2expt(t2L1, L-1)) != CRYPT_OK) { goto cleanup; }
115 /* t2L1 = 2^(L-1) */
116 if ((err = mp_2expt(t2N1, N-1)) != CRYPT_OK) { goto cleanup; }
117 /* t2N1 = 2^(N-1) */
118 if ((err = mp_2expt(t2seedlen, seedbytes*8)) != CRYPT_OK) { goto cleanup; }
119 /* t2seedlen = 2^seedlen */
120
121 for(found_p=0; !found_p;) {
122 /* q */
123 for(found_q=0; !found_q;) {
124 if (prng_descriptor[wprng]->read(sbuf, seedbytes, prng) != seedbytes) { err = CRYPT_ERROR_READPRNG; goto cleanup; }
125 i = outbytes;
126 if ((err = hash_memory(hash, sbuf, seedbytes, digest, &i)) != CRYPT_OK) { goto cleanup; }
127 if ((err = mp_read_unsigned_bin(U, digest, outbytes)) != CRYPT_OK) { goto cleanup; }
128 if ((err = mp_mod(U, t2N1, U)) != CRYPT_OK) { goto cleanup; }
129 if ((err = mp_add(t2N1, U, q)) != CRYPT_OK) { goto cleanup; }
130 if (!mp_isodd(q)) mp_add_d(q, 1, q);
131 if ((err = mp_prime_is_prime(q, mr_tests_q, &res)) != CRYPT_OK) { goto cleanup; }
132 if (res == LTC_MP_YES) found_q = 1;
133 }
134
135 /* p */
136 if ((err = mp_read_unsigned_bin(seedinc, sbuf, seedbytes)) != CRYPT_OK) { goto cleanup; }
137 if ((err = mp_add(q, q, t2q)) != CRYPT_OK) { goto cleanup; }
138 for(counter=0; counter < 4*L && !found_p; counter++) {
139 for(j=0; j<=n; j++) {
140 if ((err = mp_add_d(seedinc, 1, seedinc)) != CRYPT_OK) { goto cleanup; }
141 if ((err = mp_mod(seedinc, t2seedlen, seedinc)) != CRYPT_OK) { goto cleanup; }
142 /* seedinc = (seedinc+1) % 2^seed_bitlen */
143 if ((i = mp_unsigned_bin_size(seedinc)) > seedbytes) { err = CRYPT_INVALID_ARG; goto cleanup; }
144 zeromem(sbuf, seedbytes);
145 if ((err = mp_to_unsigned_bin(seedinc, sbuf + seedbytes-i)) != CRYPT_OK) { goto cleanup; }
146 i = outbytes;
147 err = hash_memory(hash, sbuf, seedbytes, wbuf+(n-j)*outbytes, &i);
148 if (err != CRYPT_OK) { goto cleanup; }
149 }
150 if ((err = mp_read_unsigned_bin(W, wbuf, (n+1)*outbytes)) != CRYPT_OK) { goto cleanup; }
151 if ((err = mp_mod(W, t2L1, W)) != CRYPT_OK) { goto cleanup; }
152 if ((err = mp_add(W, t2L1, X)) != CRYPT_OK) { goto cleanup; }
153 if ((err = mp_mod(X, t2q, c)) != CRYPT_OK) { goto cleanup; }
154 if ((err = mp_sub_d(c, 1, p)) != CRYPT_OK) { goto cleanup; }
155 if ((err = mp_sub(X, p, p)) != CRYPT_OK) { goto cleanup; }
156 if (mp_cmp(p, t2L1) != LTC_MP_LT) {
157 /* p >= 2^(L-1) */
158 if ((err = mp_prime_is_prime(p, mr_tests_p, &res)) != CRYPT_OK) { goto cleanup; }
159 if (res == LTC_MP_YES) {
160 found_p = 1;
161 }
162 }
163 }
164 }
165
166 /* FIPS-186-4 A.2.1 Unverifiable Generation of the Generator g
167 * 1. e = (p - 1)/q
168 * 2. h = any integer satisfying: 1 < h < (p - 1)
169 * h could be obtained from a random number generator or from a counter that changes after each use
170 * 3. g = h^e mod p
171 * 4. if (g == 1), then go to step 2.
172 *
173 */
174
175 if ((err = mp_sub_d(p, 1, e)) != CRYPT_OK) { goto cleanup; }
176 if ((err = mp_div(e, q, e, c)) != CRYPT_OK) { goto cleanup; }
177 /* e = (p - 1)/q */
178 i = mp_count_bits(p);
179 do {
180 do {
181 if ((err = rand_bn_bits(h, i, prng, wprng)) != CRYPT_OK) { goto cleanup; }
182 } while (mp_cmp(h, p) != LTC_MP_LT || mp_cmp_d(h, 2) != LTC_MP_GT);
183 if ((err = mp_sub_d(h, 1, h)) != CRYPT_OK) { goto cleanup; }
184 /* h is randon and 1 < h < (p-1) */
185 if ((err = mp_exptmod(h, e, p, g)) != CRYPT_OK) { goto cleanup; }
186 } while (mp_cmp_d(g, 1) == LTC_MP_EQ);
187
188 err = CRYPT_OK;
189 cleanup:
190 mp_clear_multi(t2L1, t2N1, t2q, t2seedlen, U, W, X, c, h, e, seedinc, LTC_NULL);
191 cleanup1:
192 XFREE(sbuf);
193 cleanup2:
194 XFREE(wbuf);
195 cleanup3:
196 return err;
197 }
198
199 /**
200 Generate DSA parameters p, q & g
201 @param prng An active PRNG state
202 @param wprng The index of the PRNG desired
203 @param group_size Size of the multiplicative group (octets)
204 @param modulus_size Size of the modulus (octets)
205 @param key [out] Where to store the created key
206 @return CRYPT_OK if successful.
207 */
dsa_generate_pqg(prng_state * prng,int wprng,int group_size,int modulus_size,dsa_key * key)208 int dsa_generate_pqg(prng_state *prng, int wprng, int group_size, int modulus_size, dsa_key *key)
209 {
210 int err;
211
212 LTC_ARGCHK(key != NULL);
213 LTC_ARGCHK(ltc_mp.name != NULL);
214
215 /* init mp_ints */
216 if ((err = mp_init_multi(&key->p, &key->g, &key->q, &key->x, &key->y, LTC_NULL)) != CRYPT_OK) {
217 return err;
218 }
219 /* generate params */
220 err = s_dsa_make_params(prng, wprng, group_size, modulus_size, key->p, key->q, key->g);
221 if (err != CRYPT_OK) {
222 goto cleanup;
223 }
224
225 key->qord = group_size;
226
227 return CRYPT_OK;
228
229 cleanup:
230 dsa_free(key);
231 return err;
232 }
233
234 #endif
235