3
|
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 * Tom St Denis, [email protected], http://libtomcrypt.org |
|
10 */ |
|
11 #include "mycrypt.h" |
|
12 |
|
13 #ifdef MDH |
|
14 |
|
15 /* This holds the key settings. ***MUST*** be organized by size from smallest to largest. */ |
|
16 static const struct { |
|
17 int size; |
|
18 char *name, *base, *prime; |
|
19 } sets[] = { |
|
20 #ifdef DH768 |
|
21 { |
|
22 96, |
|
23 "DH-768", |
|
24 "4", |
|
25 "F///////////////////////////////////////////////////////////" |
|
26 "////////////////////////////////////////////////////////////" |
|
27 "//////m3wvV" |
|
28 }, |
|
29 #endif |
|
30 #ifdef DH1024 |
|
31 { |
|
32 128, |
|
33 "DH-1024", |
|
34 "4", |
|
35 "F///////////////////////////////////////////////////////////" |
|
36 "////////////////////////////////////////////////////////////" |
|
37 "////////////////////////////////////////////////m3C47" |
|
38 }, |
|
39 #endif |
|
40 #ifdef DH1280 |
|
41 { |
|
42 160, |
|
43 "DH-1280", |
|
44 "4", |
|
45 "F///////////////////////////////////////////////////////////" |
|
46 "////////////////////////////////////////////////////////////" |
|
47 "////////////////////////////////////////////////////////////" |
|
48 "//////////////////////////////m4kSN" |
|
49 }, |
|
50 #endif |
|
51 #ifdef DH1536 |
|
52 { |
|
53 192, |
|
54 "DH-1536", |
|
55 "4", |
|
56 "F///////////////////////////////////////////////////////////" |
|
57 "////////////////////////////////////////////////////////////" |
|
58 "////////////////////////////////////////////////////////////" |
|
59 "////////////////////////////////////////////////////////////" |
|
60 "////////////m5uqd" |
|
61 }, |
|
62 #endif |
|
63 #ifdef DH1792 |
|
64 { |
|
65 224, |
|
66 "DH-1792", |
|
67 "4", |
|
68 "F///////////////////////////////////////////////////////////" |
|
69 "////////////////////////////////////////////////////////////" |
|
70 "////////////////////////////////////////////////////////////" |
|
71 "////////////////////////////////////////////////////////////" |
|
72 "//////////////////////////////////////////////////////mT/sd" |
|
73 }, |
|
74 #endif |
|
75 #ifdef DH2048 |
|
76 { |
|
77 256, |
|
78 "DH-2048", |
|
79 "4", |
|
80 "3///////////////////////////////////////////////////////////" |
|
81 "////////////////////////////////////////////////////////////" |
|
82 "////////////////////////////////////////////////////////////" |
|
83 "////////////////////////////////////////////////////////////" |
|
84 "////////////////////////////////////////////////////////////" |
|
85 "/////////////////////////////////////////m8MPh" |
|
86 }, |
|
87 #endif |
|
88 #ifdef DH2560 |
|
89 { |
|
90 320, |
|
91 "DH-2560", |
|
92 "4", |
|
93 "3///////////////////////////////////////////////////////////" |
|
94 "////////////////////////////////////////////////////////////" |
|
95 "////////////////////////////////////////////////////////////" |
|
96 "////////////////////////////////////////////////////////////" |
|
97 "////////////////////////////////////////////////////////////" |
|
98 "////////////////////////////////////////////////////////////" |
|
99 "////////////////////////////////////////////////////////////" |
|
100 "/////mKFpF" |
|
101 }, |
|
102 #endif |
|
103 #ifdef DH3072 |
|
104 { |
|
105 384, |
|
106 "DH-3072", |
|
107 "4", |
|
108 "3///////////////////////////////////////////////////////////" |
|
109 "////////////////////////////////////////////////////////////" |
|
110 "////////////////////////////////////////////////////////////" |
|
111 "////////////////////////////////////////////////////////////" |
|
112 "////////////////////////////////////////////////////////////" |
|
113 "////////////////////////////////////////////////////////////" |
|
114 "////////////////////////////////////////////////////////////" |
|
115 "////////////////////////////////////////////////////////////" |
|
116 "/////////////////////////////m32nN" |
|
117 }, |
|
118 #endif |
|
119 #ifdef DH4096 |
|
120 { |
|
121 512, |
|
122 "DH-4096", |
|
123 "4", |
|
124 "////////////////////////////////////////////////////////////" |
|
125 "////////////////////////////////////////////////////////////" |
|
126 "////////////////////////////////////////////////////////////" |
|
127 "////////////////////////////////////////////////////////////" |
|
128 "////////////////////////////////////////////////////////////" |
|
129 "////////////////////////////////////////////////////////////" |
|
130 "////////////////////////////////////////////////////////////" |
|
131 "////////////////////////////////////////////////////////////" |
|
132 "////////////////////////////////////////////////////////////" |
|
133 "////////////////////////////////////////////////////////////" |
|
134 "////////////////////////////////////////////////////////////" |
|
135 "/////////////////////m8pOF" |
|
136 }, |
|
137 #endif |
|
138 { |
|
139 0, |
|
140 NULL, |
|
141 NULL, |
|
142 NULL |
|
143 } |
|
144 }; |
|
145 |
|
146 static int is_valid_idx(int n) |
|
147 { |
|
148 int x; |
|
149 |
|
150 for (x = 0; sets[x].size; x++); |
|
151 if ((n < 0) || (n >= x)) { |
|
152 return 0; |
|
153 } |
|
154 return 1; |
|
155 } |
|
156 |
|
157 int dh_test(void) |
|
158 { |
|
159 mp_int p, g, tmp; |
|
160 int x, err, primality; |
|
161 |
|
162 if ((err = mp_init_multi(&p, &g, &tmp, NULL)) != MP_OKAY) { goto error; } |
|
163 |
|
164 for (x = 0; sets[x].size != 0; x++) { |
|
165 #if 0 |
|
166 printf("dh_test():testing size %d-bits\n", sets[x].size * 8); |
|
167 #endif |
|
168 if ((err = mp_read_radix(&g,(char *)sets[x].base, 64)) != MP_OKAY) { goto error; } |
|
169 if ((err = mp_read_radix(&p,(char *)sets[x].prime, 64)) != MP_OKAY) { goto error; } |
|
170 |
|
171 /* ensure p is prime */ |
|
172 if ((err = is_prime(&p, &primality)) != CRYPT_OK) { goto done; } |
|
173 if (primality == 0) { |
|
174 err = CRYPT_FAIL_TESTVECTOR; |
|
175 goto done; |
|
176 } |
|
177 |
|
178 if ((err = mp_sub_d(&p, 1, &tmp)) != MP_OKAY) { goto error; } |
|
179 if ((err = mp_div_2(&tmp, &tmp)) != MP_OKAY) { goto error; } |
|
180 |
|
181 /* ensure (p-1)/2 is prime */ |
|
182 if ((err = is_prime(&tmp, &primality)) != CRYPT_OK) { goto done; } |
|
183 if (primality == 0) { |
|
184 err = CRYPT_FAIL_TESTVECTOR; |
|
185 goto done; |
|
186 } |
|
187 |
|
188 /* now see if g^((p-1)/2) mod p is in fact 1 */ |
|
189 if ((err = mp_exptmod(&g, &tmp, &p, &tmp)) != MP_OKAY) { goto error; } |
|
190 if (mp_cmp_d(&tmp, 1)) { |
|
191 err = CRYPT_FAIL_TESTVECTOR; |
|
192 goto done; |
|
193 } |
|
194 } |
|
195 err = CRYPT_OK; |
|
196 goto done; |
|
197 error: |
|
198 err = mpi_to_ltc_error(err); |
|
199 done: |
|
200 mp_clear_multi(&tmp, &g, &p, NULL); |
|
201 return err; |
|
202 } |
|
203 |
|
204 void dh_sizes(int *low, int *high) |
|
205 { |
|
206 int x; |
|
207 _ARGCHK(low != NULL); |
|
208 _ARGCHK(high != NULL); |
|
209 *low = INT_MAX; |
|
210 *high = 0; |
|
211 for (x = 0; sets[x].size != 0; x++) { |
|
212 if (*low > sets[x].size) *low = sets[x].size; |
|
213 if (*high < sets[x].size) *high = sets[x].size; |
|
214 } |
|
215 } |
|
216 |
|
217 int dh_get_size(dh_key *key) |
|
218 { |
|
219 _ARGCHK(key != NULL); |
|
220 if (is_valid_idx(key->idx) == 1) { |
|
221 return sets[key->idx].size; |
|
222 } else { |
|
223 return INT_MAX; /* large value that would cause dh_make_key() to fail */ |
|
224 } |
|
225 } |
|
226 |
|
227 int dh_make_key(prng_state *prng, int wprng, int keysize, dh_key *key) |
|
228 { |
|
229 unsigned char buf[512]; |
|
230 unsigned long x; |
|
231 mp_int p, g; |
|
232 int err; |
|
233 |
|
234 _ARGCHK(key != NULL); |
|
235 |
|
236 /* good prng? */ |
|
237 if ((err = prng_is_valid(wprng)) != CRYPT_OK) { |
|
238 return err; |
|
239 } |
|
240 |
|
241 /* find key size */ |
|
242 for (x = 0; (keysize > sets[x].size) && (sets[x].size != 0); x++); |
|
243 #ifdef FAST_PK |
|
244 keysize = MIN(sets[x].size, 32); |
|
245 #else |
|
246 keysize = sets[x].size; |
|
247 #endif |
|
248 |
|
249 if (sets[x].size == 0) { |
|
250 return CRYPT_INVALID_KEYSIZE; |
|
251 } |
|
252 key->idx = x; |
|
253 |
|
254 /* make up random string */ |
|
255 if (prng_descriptor[wprng].read(buf, keysize, prng) != (unsigned long)keysize) { |
|
256 return CRYPT_ERROR_READPRNG; |
|
257 } |
|
258 |
|
259 /* init parameters */ |
|
260 if ((err = mp_init_multi(&g, &p, &key->x, &key->y, NULL)) != MP_OKAY) { |
|
261 return mpi_to_ltc_error(err); |
|
262 } |
|
263 if ((err = mp_read_radix(&g, sets[key->idx].base, 64)) != MP_OKAY) { goto error; } |
|
264 if ((err = mp_read_radix(&p, sets[key->idx].prime, 64)) != MP_OKAY) { goto error; } |
|
265 |
|
266 /* load the x value */ |
|
267 if ((err = mp_read_unsigned_bin(&key->x, buf, keysize)) != MP_OKAY) { goto error; } |
|
268 if ((err = mp_exptmod(&g, &key->x, &p, &key->y)) != MP_OKAY) { goto error; } |
|
269 key->type = PK_PRIVATE; |
|
270 |
|
271 if ((err = mp_shrink(&key->x)) != MP_OKAY) { goto error; } |
|
272 if ((err = mp_shrink(&key->y)) != MP_OKAY) { goto error; } |
|
273 |
|
274 /* free up ram */ |
|
275 err = CRYPT_OK; |
|
276 goto done; |
|
277 error: |
|
278 err = mpi_to_ltc_error(err); |
|
279 mp_clear_multi(&key->x, &key->y, NULL); |
|
280 done: |
|
281 mp_clear_multi(&p, &g, NULL); |
|
282 zeromem(buf, sizeof(buf)); |
|
283 return err; |
|
284 } |
|
285 |
|
286 void dh_free(dh_key *key) |
|
287 { |
|
288 _ARGCHK(key != NULL); |
|
289 mp_clear_multi(&key->x, &key->y, NULL); |
|
290 } |
|
291 |
|
292 int dh_export(unsigned char *out, unsigned long *outlen, int type, dh_key *key) |
|
293 { |
|
294 unsigned long y, z; |
|
295 int err; |
|
296 |
|
297 _ARGCHK(out != NULL); |
|
298 _ARGCHK(outlen != NULL); |
|
299 _ARGCHK(key != NULL); |
|
300 |
|
301 /* can we store the static header? */ |
|
302 if (*outlen < (PACKET_SIZE + 2)) { |
|
303 return CRYPT_BUFFER_OVERFLOW; |
|
304 } |
|
305 |
|
306 if (type == PK_PRIVATE && key->type != PK_PRIVATE) { |
|
307 return CRYPT_PK_NOT_PRIVATE; |
|
308 } |
|
309 |
|
310 /* header */ |
|
311 y = PACKET_SIZE; |
|
312 |
|
313 /* header */ |
|
314 out[y++] = type; |
|
315 out[y++] = (unsigned char)(sets[key->idx].size / 8); |
|
316 |
|
317 /* export y */ |
|
318 OUTPUT_BIGNUM(&key->y, out, y, z); |
|
319 |
|
320 if (type == PK_PRIVATE) { |
|
321 /* export x */ |
|
322 OUTPUT_BIGNUM(&key->x, out, y, z); |
|
323 } |
|
324 |
|
325 /* store header */ |
|
326 packet_store_header(out, PACKET_SECT_DH, PACKET_SUB_KEY); |
|
327 |
|
328 /* store len */ |
|
329 *outlen = y; |
|
330 return CRYPT_OK; |
|
331 } |
|
332 |
|
333 int dh_import(const unsigned char *in, unsigned long inlen, dh_key *key) |
|
334 { |
|
335 unsigned long x, y, s; |
|
336 int err; |
|
337 |
|
338 _ARGCHK(in != NULL); |
|
339 _ARGCHK(key != NULL); |
|
340 |
|
341 /* make sure valid length */ |
|
342 if ((2+PACKET_SIZE) > inlen) { |
|
343 return CRYPT_INVALID_PACKET; |
|
344 } |
|
345 |
|
346 /* check type byte */ |
|
347 if ((err = packet_valid_header((unsigned char *)in, PACKET_SECT_DH, PACKET_SUB_KEY)) != CRYPT_OK) { |
|
348 return err; |
|
349 } |
|
350 |
|
351 /* init */ |
|
352 if ((err = mp_init_multi(&key->x, &key->y, NULL)) != MP_OKAY) { |
|
353 return mpi_to_ltc_error(err); |
|
354 } |
|
355 |
|
356 /* advance past packet header */ |
|
357 y = PACKET_SIZE; |
|
358 |
|
359 /* key type, e.g. private, public */ |
|
360 key->type = (int)in[y++]; |
|
361 |
|
362 /* key size in bytes */ |
|
363 s = (unsigned long)in[y++] * 8; |
|
364 |
|
365 for (x = 0; (s > (unsigned long)sets[x].size) && (sets[x].size != 0); x++); |
|
366 if (sets[x].size == 0) { |
|
367 err = CRYPT_INVALID_KEYSIZE; |
|
368 goto error; |
|
369 } |
|
370 key->idx = (int)x; |
|
371 |
|
372 /* type check both values */ |
|
373 if ((key->type != PK_PUBLIC) && (key->type != PK_PRIVATE)) { |
|
374 err = CRYPT_PK_TYPE_MISMATCH; |
|
375 goto error; |
|
376 } |
|
377 |
|
378 /* is the key idx valid? */ |
|
379 if (is_valid_idx(key->idx) != 1) { |
|
380 err = CRYPT_PK_TYPE_MISMATCH; |
|
381 goto error; |
|
382 } |
|
383 |
|
384 /* load public value g^x mod p*/ |
|
385 INPUT_BIGNUM(&key->y, in, x, y, inlen); |
|
386 |
|
387 if (key->type == PK_PRIVATE) { |
|
388 INPUT_BIGNUM(&key->x, in, x, y, inlen); |
|
389 } |
|
390 |
|
391 /* eliminate private key if public */ |
|
392 if (key->type == PK_PUBLIC) { |
|
393 mp_clear(&key->x); |
|
394 } |
|
395 |
|
396 return CRYPT_OK; |
|
397 error: |
|
398 mp_clear_multi(&key->y, &key->x, NULL); |
|
399 return err; |
|
400 } |
|
401 |
|
402 int dh_shared_secret(dh_key *private_key, dh_key *public_key, |
|
403 unsigned char *out, unsigned long *outlen) |
|
404 { |
|
405 mp_int tmp, p; |
|
406 unsigned long x; |
|
407 int err; |
|
408 |
|
409 _ARGCHK(private_key != NULL); |
|
410 _ARGCHK(public_key != NULL); |
|
411 _ARGCHK(out != NULL); |
|
412 _ARGCHK(outlen != NULL); |
|
413 |
|
414 /* types valid? */ |
|
415 if (private_key->type != PK_PRIVATE) { |
|
416 return CRYPT_PK_NOT_PRIVATE; |
|
417 } |
|
418 |
|
419 /* same idx? */ |
|
420 if (private_key->idx != public_key->idx) { |
|
421 return CRYPT_PK_TYPE_MISMATCH; |
|
422 } |
|
423 |
|
424 /* compute y^x mod p */ |
|
425 if ((err = mp_init_multi(&tmp, &p, NULL)) != MP_OKAY) { |
|
426 return mpi_to_ltc_error(err); |
|
427 } |
|
428 |
|
429 if ((err = mp_read_radix(&p, (char *)sets[private_key->idx].prime, 64)) != MP_OKAY) { goto error; } |
|
430 if ((err = mp_exptmod(&public_key->y, &private_key->x, &p, &tmp)) != MP_OKAY) { goto error; } |
|
431 |
|
432 /* enough space for output? */ |
|
433 x = (unsigned long)mp_unsigned_bin_size(&tmp); |
|
434 if (*outlen < x) { |
|
435 err = CRYPT_BUFFER_OVERFLOW; |
|
436 goto done; |
|
437 } |
|
438 if ((err = mp_to_unsigned_bin(&tmp, out)) != MP_OKAY) { goto error; } |
|
439 *outlen = x; |
|
440 err = CRYPT_OK; |
|
441 goto done; |
|
442 error: |
|
443 err = mpi_to_ltc_error(err); |
|
444 done: |
|
445 mp_clear_multi(&p, &tmp, NULL); |
|
446 return err; |
|
447 } |
|
448 |
|
449 #include "dh_sys.c" |
|
450 |
|
451 #endif |
|
452 |