Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/tomcrypt/src/pk/dsa/dsa_generate_pqg.c
4396 views
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 = (unsigned long)modulus_size * 8;
76
N = (unsigned long)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