DSA params+key generation according FIPS-186-4 (part 1)
Karel Miko
10 years ago
17 | 17 | #ifdef LTC_MDSA |
18 | 18 | |
19 | 19 | /** |
20 | Create DSA parameters | |
21 | @param prng An active PRNG state | |
22 | @param wprng The index of the PRNG desired | |
23 | @param group_size Size of the multiplicative group (octets) | |
24 | @param modulus_size Size of the modulus (octets) | |
25 | @param p [out] bignum where generated 'p' is stored (must be initialized by caller) | |
26 | @param q [out] bignum where generated 'q' is stored (must be initialized by caller) | |
27 | @param g [out] bignum where generated 'g' is stored (must be initialized by caller) | |
28 | @return CRYPT_OK if successful, upon error this function will free all allocated memory | |
29 | */ | |
30 | int dsa_make_params(prng_state *prng, int wprng, int group_size, int modulus_size, void *p, void *q, void *g) | |
31 | { | |
32 | unsigned long L, N, n, outbytes, seedbytes, counter, j, i; | |
33 | int err, res, mr_tests_q, mr_tests_p, found_p, found_q, hash; | |
34 | unsigned char *wbuf, *sbuf, digest[MAXBLOCKSIZE]; | |
35 | void *t2L1, *t2N1, *t2q, *t2seedlen, *U, *W, *X, *c, *h, *e, *seedinc; | |
36 | ||
37 | /* check size */ | |
38 | if (group_size >= LTC_MDSA_MAX_GROUP || group_size < 1 || group_size >= modulus_size) { | |
39 | return CRYPT_INVALID_ARG; | |
40 | } | |
41 | ||
42 | /* FIPS-186-4 A.1.1.2 Generation of the Probable Primes p and q Using an Approved Hash Function | |
43 | * | |
44 | * L = The desired length of the prime p (in bits e.g. L = 1024) | |
45 | * N = The desired length of the prime q (in bits e.g. N = 160) | |
46 | * seedlen = The desired bit length of the domain parameter seed; seedlen shallbe equal to or greater than N | |
47 | * outlen = The bit length of Hash function | |
48 | * | |
49 | * 1. Check that the (L, N) | |
50 | * 2. If (seedlen <N), then return INVALID. | |
51 | * 3. n = ceil(L / outlen) - 1 | |
52 | * 4. b = L- 1 - (n * outlen) | |
53 | * 5. domain_parameter_seed = an arbitrary sequence of seedlen bits | |
54 | * 6. U = Hash (domain_parameter_seed) mod 2^(N-1) | |
55 | * 7. q = 2^(N-1) + U + 1 - (U mod 2) | |
56 | * 8. Test whether or not q is prime as specified in Appendix C.3 | |
57 | * 9. If qis not a prime, then go to step 5. | |
58 | * 10. offset = 1 | |
59 | * 11. For counter = 0 to (4L- 1) do { | |
60 | * For j=0 to n do { | |
61 | * Vj = Hash ((domain_parameter_seed+ offset + j) mod 2^seedlen | |
62 | * } | |
63 | * W = V0 + (V1 *2^outlen) + ... + (Vn-1 * 2^((n-1) * outlen)) + ((Vn mod 2^b) * 2^(n * outlen)) | |
64 | * X = W + 2^(L-1) Comment: 0 <= W < 2^(L-1); hence 2^(L-1) <= X < 2^L | |
65 | * c = X mod 2*q | |
66 | * p = X - (c - 1) Comment: p ~ 1 (mod 2*q) | |
67 | * If (p >= 2^(L-1)) { | |
68 | * Test whether or not p is prime as specified in Appendix C.3. | |
69 | * 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 | |
70 | * } | |
71 | * offset = offset + n + 1 Comment: Increment offset | |
72 | * } | |
73 | */ | |
74 | ||
75 | seedbytes = group_size; | |
76 | L = modulus_size * 8; | |
77 | N = group_size * 8; | |
78 | ||
79 | /* M-R tests (when followed by one Lucas test) according FIPS-186-4 - Appendix C.3 - table C.1 */ | |
80 | mr_tests_p = (L <= 2048) ? 3 : 2; | |
81 | if (N <= 160) { mr_tests_q = 19; } | |
82 | else if (N <= 224) { mr_tests_q = 24; } | |
83 | else { mr_tests_q = 27; } | |
84 | ||
85 | if (N <= 256) { | |
86 | hash = register_hash(&sha256_desc); | |
87 | } | |
88 | else if (N <= 384) { | |
89 | hash = register_hash(&sha384_desc); | |
90 | } | |
91 | else if (N <= 512) { | |
92 | hash = register_hash(&sha512_desc); | |
93 | } | |
94 | else { | |
95 | return CRYPT_INVALID_ARG; /* group_size too big */ | |
96 | } | |
97 | ||
98 | if ((err = hash_is_valid(hash)) != CRYPT_OK) { return err; } | |
99 | outbytes = hash_descriptor[hash].hashsize; | |
100 | ||
101 | n = ((L + outbytes*8 - 1) / (outbytes*8)) - 1; | |
102 | ||
103 | if ((wbuf = XMALLOC((n+1)*outbytes)) == NULL) { err = CRYPT_MEM; goto cleanup3; } | |
104 | if ((sbuf = XMALLOC(seedbytes)) == NULL) { err = CRYPT_MEM; goto cleanup2; } | |
105 | ||
106 | err = mp_init_multi(&t2L1, &t2N1, &t2q, &t2seedlen, &U, &W, &X, &c, &h, &e, &seedinc, NULL); | |
107 | if (err != CRYPT_OK) { goto cleanup1; }; | |
108 | ||
109 | if ((err = mp_2expt(t2L1, L-1)) != CRYPT_OK) { goto cleanup; } | |
110 | /* t2L1 = 2^(L-1) */ | |
111 | if ((err = mp_2expt(t2N1, N-1)) != CRYPT_OK) { goto cleanup; } | |
112 | /* t2N1 = 2^(N-1) */ | |
113 | if ((err = mp_2expt(t2seedlen, seedbytes*8)) != CRYPT_OK) { goto cleanup; } | |
114 | /* t2seedlen = 2^seedlen */ | |
115 | ||
116 | for(found_p=0; !found_p;) { | |
117 | /* q */ | |
118 | for(found_q=0; !found_q;) { | |
119 | if (prng_descriptor[wprng].read(sbuf, seedbytes, prng) != seedbytes) { err = CRYPT_ERROR_READPRNG; goto cleanup; } | |
120 | i = outbytes; | |
121 | if ((err = hash_memory(hash, sbuf, seedbytes, digest, &i)) != CRYPT_OK) { goto cleanup; } | |
122 | if ((err = mp_read_unsigned_bin(U, digest, outbytes)) != CRYPT_OK) { goto cleanup; } | |
123 | if ((err = mp_mod(U, t2N1, U)) != CRYPT_OK) { goto cleanup; } | |
124 | if ((err = mp_add(t2N1, U, q)) != CRYPT_OK) { goto cleanup; } | |
125 | if (!mp_isodd(q)) mp_add_d(q, 1, q); | |
126 | if ((err = mp_prime_is_prime(q, mr_tests_q, &res)) != CRYPT_OK) { goto cleanup; } /* XXX-TODO rounds are ignored; no Lucas test */ | |
127 | if (res == LTC_MP_YES) found_q = 1; | |
128 | } | |
129 | ||
130 | /* p */ | |
131 | if ((err = mp_read_unsigned_bin(seedinc, sbuf, seedbytes)) != CRYPT_OK) { goto cleanup; } | |
132 | /* printf("seed="); mp_fwrite(seedinc, 16, stdout); printf("\n"); //XXX-DEBUG */ | |
133 | if ((err = mp_add(q, q, t2q)) != CRYPT_OK) { goto cleanup; } | |
134 | for(counter=0; counter < 4*L && !found_p; counter++) { | |
135 | for(j=0; j<=n; j++) { | |
136 | if ((err = mp_add_d(seedinc, 1, seedinc)) != CRYPT_OK) { goto cleanup; } | |
137 | if ((err = mp_mod(seedinc, t2seedlen, seedinc)) != CRYPT_OK) { goto cleanup; } | |
138 | /* seedinc = (seedinc+1) % 2^seed_bitlen */ | |
139 | if ((i = mp_unsigned_bin_size(seedinc)) > seedbytes) { err = CRYPT_INVALID_ARG; goto cleanup; } | |
140 | zeromem(sbuf, seedbytes); | |
141 | if ((err = mp_to_unsigned_bin(seedinc, sbuf + seedbytes-i)) != CRYPT_OK) { goto cleanup; } | |
142 | i = outbytes; | |
143 | err = hash_memory(hash, sbuf, seedbytes, wbuf+(n-j)*outbytes, &i); | |
144 | if (err != CRYPT_OK) { goto cleanup; } | |
145 | } | |
146 | if ((err = mp_read_unsigned_bin(W, wbuf, (n+1)*outbytes)) != CRYPT_OK) { goto cleanup; } | |
147 | if ((err = mp_mod(W, t2L1, W)) != CRYPT_OK) { goto cleanup; } | |
148 | if ((err = mp_add(W, t2L1, X)) != CRYPT_OK) { goto cleanup; } | |
149 | if ((err = mp_mod(X, t2q, c)) != CRYPT_OK) { goto cleanup; } | |
150 | if ((err = mp_sub_d(c, 1, p)) != CRYPT_OK) { goto cleanup; } | |
151 | if ((err = mp_sub(X, p, p)) != CRYPT_OK) { goto cleanup; } | |
152 | if (mp_cmp(p, t2L1) != LTC_MP_LT) { | |
153 | /* p >= 2^(L-1) */ | |
154 | if ((err = mp_prime_is_prime(p, mr_tests_p, &res)) != CRYPT_OK) { goto cleanup; } /* XXX-TODO rounds are ignored; no Lucas test */ | |
155 | if (res == LTC_MP_YES) { | |
156 | found_p = 1; | |
157 | } | |
158 | } | |
159 | } | |
160 | } | |
161 | ||
162 | /* FIPS-186-4 A.2.1 Unverifiable Generation of the Generator g | |
163 | * 1. e = (p - 1)/q | |
164 | * 2. h = any integer satisfying: 1 < h < (p - 1) | |
165 | * h could be obtained from a random number generator or from a counter that changes after each use | |
166 | * 3. g = h^e mod p | |
167 | * 4. if (g == 1), then go to step 2. | |
168 | * | |
169 | */ | |
170 | ||
171 | if ((err = mp_sub_d(p, 1, e)) != CRYPT_OK) { goto cleanup; } | |
172 | if ((err = mp_div(e, q, e, c)) != CRYPT_OK) { goto cleanup; } | |
173 | /* e = (p - 1)/q */ | |
174 | i = mp_count_bits(p); | |
175 | do { | |
176 | do { | |
177 | if ((err = rand_bn_bits(h, i, prng, wprng)) != CRYPT_OK) { goto cleanup; } | |
178 | } while (mp_cmp(h, p) != LTC_MP_LT || mp_cmp_d(h, 2) != LTC_MP_GT); | |
179 | if ((err = mp_sub_d(h, 1, h)) != CRYPT_OK) { goto cleanup; } | |
180 | /* h is randon and 1 < h < (p-1) */ | |
181 | if ((err = mp_exptmod(h, e, p, g)) != CRYPT_OK) { goto cleanup; } | |
182 | } while (mp_cmp_d(g, 1) == LTC_MP_EQ); | |
183 | ||
184 | err = CRYPT_OK; | |
185 | cleanup: | |
186 | mp_clear_multi(t2L1, t2N1, t2q, t2seedlen, U, W, X, c, h, e, seedinc, NULL); | |
187 | cleanup1: | |
188 | XFREE(wbuf); | |
189 | cleanup2: | |
190 | XFREE(wbuf); | |
191 | cleanup3: | |
192 | return err; | |
193 | } | |
194 | ||
195 | /** | |
196 | Create a DSA key (with given params) | |
197 | @param prng An active PRNG state | |
198 | @param wprng The index of the PRNG desired | |
199 | @param group_size Size of the multiplicative group (octets) | |
200 | @param modulus_size Size of the modulus (octets) | |
201 | @param key [out] Where to store the created key | |
202 | @param p_hex Hexadecimal string 'p' | |
203 | @param q_hex Hexadecimal string 'q' | |
204 | @param g_hex Hexadecimal string 'g' | |
205 | @return CRYPT_OK if successful, upon error this function will free all allocated memory | |
206 | */ | |
207 | int dsa_make_key_ex(prng_state *prng, int wprng, int group_size, int modulus_size, dsa_key *key, char* p_hex, char* q_hex, char* g_hex) | |
208 | { | |
209 | int err, qbits; | |
210 | ||
211 | LTC_ARGCHK(key != NULL); | |
212 | ||
213 | /* init mp_ints */ | |
214 | if ((err = mp_init_multi(&key->g, &key->q, &key->p, &key->x, &key->y, NULL)) != CRYPT_OK) { | |
215 | return err; | |
216 | } | |
217 | ||
218 | if (p_hex == NULL || q_hex == NULL || g_hex == NULL) { | |
219 | /* generate params */ | |
220 | err = dsa_make_params(prng, wprng, group_size, modulus_size, key->p, key->q, key->g); | |
221 | if (err != CRYPT_OK) { goto cleanup; } | |
222 | } | |
223 | else { | |
224 | /* read params */ | |
225 | if ((err = mp_read_radix(key->p, p_hex, 16)) != CRYPT_OK) { goto cleanup; } | |
226 | if ((err = mp_read_radix(key->q, q_hex, 16)) != CRYPT_OK) { goto cleanup; } | |
227 | if ((err = mp_read_radix(key->g, g_hex, 16)) != CRYPT_OK) { goto cleanup; } | |
228 | /* XXX-TODO maybe do some validity check for p, q, g */ | |
229 | } | |
230 | ||
231 | /* so now we have our DH structure, generator g, order q, modulus p | |
232 | Now we need a random exponent [mod q] and it's power g^x mod p | |
233 | */ | |
234 | qbits = mp_count_bits(key->q); | |
235 | do { | |
236 | if ((err = rand_bn_bits(key->x, qbits, prng, wprng)) != CRYPT_OK) { goto cleanup; } | |
237 | /* private key x should be from range: 1 <= x <= q-1 (see FIPS 186-4 B.1.2) */ | |
238 | } while (mp_cmp_d(key->x, 0) != LTC_MP_GT || mp_cmp(key->x, key->q) != LTC_MP_LT); | |
239 | if ((err = mp_exptmod(key->g, key->x, key->p, key->y)) != CRYPT_OK) { goto cleanup; } | |
240 | key->type = PK_PRIVATE; | |
241 | key->qord = group_size; | |
242 | ||
243 | return CRYPT_OK; | |
244 | ||
245 | cleanup: | |
246 | mp_clear_multi(key->g, key->q, key->p, key->x, key->y, NULL); | |
247 | return err; | |
248 | } | |
249 | ||
250 | /** | |
20 | 251 | Create a DSA key |
21 | 252 | @param prng An active PRNG state |
22 | 253 | @param wprng The index of the PRNG desired |
27 | 258 | */ |
28 | 259 | int dsa_make_key(prng_state *prng, int wprng, int group_size, int modulus_size, dsa_key *key) |
29 | 260 | { |
30 | void *tmp, *tmp2; | |
31 | int err, res, qbits; | |
32 | unsigned char *buf; | |
33 | ||
34 | LTC_ARGCHK(key != NULL); | |
35 | LTC_ARGCHK(ltc_mp.name != NULL); | |
36 | ||
37 | /* check prng */ | |
38 | if ((err = prng_is_valid(wprng)) != CRYPT_OK) { | |
39 | return err; | |
40 | } | |
41 | ||
42 | /* check size */ | |
43 | if (group_size >= LTC_MDSA_MAX_GROUP || group_size <= 15 || | |
44 | group_size >= modulus_size || (modulus_size - group_size) >= LTC_MDSA_DELTA) { | |
45 | return CRYPT_INVALID_ARG; | |
46 | } | |
47 | ||
48 | /* allocate ram */ | |
49 | buf = XMALLOC(LTC_MDSA_DELTA); | |
50 | if (buf == NULL) { | |
51 | return CRYPT_MEM; | |
52 | } | |
53 | ||
54 | /* init mp_ints */ | |
55 | if ((err = mp_init_multi(&tmp, &tmp2, &key->g, &key->q, &key->p, &key->x, &key->y, NULL)) != CRYPT_OK) { | |
56 | XFREE(buf); | |
57 | return err; | |
58 | } | |
59 | ||
60 | /* make our prime q */ | |
61 | if ((err = rand_prime(key->q, group_size, prng, wprng)) != CRYPT_OK) { goto error; } | |
62 | ||
63 | /* double q */ | |
64 | if ((err = mp_add(key->q, key->q, tmp)) != CRYPT_OK) { goto error; } | |
65 | ||
66 | /* now make a random string and multply it against q */ | |
67 | if (prng_descriptor[wprng].read(buf, modulus_size - group_size, prng) != (unsigned long)(modulus_size - group_size)) { | |
68 | err = CRYPT_ERROR_READPRNG; | |
69 | goto error; | |
70 | } | |
71 | ||
72 | /* force magnitude */ | |
73 | buf[0] |= 0xC0; | |
74 | ||
75 | /* force even */ | |
76 | buf[modulus_size - group_size - 1] &= ~1; | |
77 | ||
78 | if ((err = mp_read_unsigned_bin(tmp2, buf, modulus_size - group_size)) != CRYPT_OK) { goto error; } | |
79 | if ((err = mp_mul(key->q, tmp2, key->p)) != CRYPT_OK) { goto error; } | |
80 | if ((err = mp_add_d(key->p, 1, key->p)) != CRYPT_OK) { goto error; } | |
81 | ||
82 | /* now loop until p is prime */ | |
83 | for (;;) { | |
84 | if ((err = mp_prime_is_prime(key->p, 8, &res)) != CRYPT_OK) { goto error; } | |
85 | if (res == LTC_MP_YES) break; | |
86 | ||
87 | /* add 2q to p and 2 to tmp2 */ | |
88 | if ((err = mp_add(tmp, key->p, key->p)) != CRYPT_OK) { goto error; } | |
89 | if ((err = mp_add_d(tmp2, 2, tmp2)) != CRYPT_OK) { goto error; } | |
90 | } | |
91 | ||
92 | /* now p = (q * tmp2) + 1 is prime, find a value g for which g^tmp2 != 1 */ | |
93 | mp_set(key->g, 1); | |
94 | ||
95 | do { | |
96 | if ((err = mp_add_d(key->g, 1, key->g)) != CRYPT_OK) { goto error; } | |
97 | if ((err = mp_exptmod(key->g, tmp2, key->p, tmp)) != CRYPT_OK) { goto error; } | |
98 | } while (mp_cmp_d(tmp, 1) == LTC_MP_EQ); | |
99 | ||
100 | /* at this point tmp generates a group of order q mod p */ | |
101 | mp_exch(tmp, key->g); | |
102 | ||
103 | /* so now we have our DH structure, generator g, order q, modulus p | |
104 | Now we need a random exponent [mod q] and it's power g^x mod p | |
105 | */ | |
106 | qbits = mp_count_bits(key->q); | |
107 | do { | |
108 | if ((err = rand_bn_bits(key->x, qbits, prng, wprng)) != CRYPT_OK) { goto error; } | |
109 | /* private key x should be from range: 1 <= x <= q-1 (see FIPS 186-4 B.1.2) */ | |
110 | } while (mp_cmp_d(key->x, 0) != LTC_MP_GT || mp_cmp(key->x, key->q) != LTC_MP_LT); | |
111 | if ((err = mp_exptmod(key->g, key->x, key->p, key->y)) != CRYPT_OK) { goto error; } | |
112 | ||
113 | key->type = PK_PRIVATE; | |
114 | key->qord = group_size; | |
115 | ||
116 | #ifdef LTC_CLEAN_STACK | |
117 | zeromem(buf, LTC_MDSA_DELTA); | |
118 | #endif | |
119 | ||
120 | err = CRYPT_OK; | |
121 | goto done; | |
122 | error: | |
123 | mp_clear_multi(key->g, key->q, key->p, key->x, key->y, NULL); | |
124 | done: | |
125 | mp_clear_multi(tmp, tmp2, NULL); | |
126 | XFREE(buf); | |
127 | return err; | |
261 | return dsa_make_key_ex(prng, wprng, group_size, modulus_size, key, NULL, NULL, NULL); | |
128 | 262 | } |
129 | 263 | |
130 | 264 | #endif |