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