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