comparison src/pk/dh/dh.c @ 192:9cc34777b479 libtomcrypt

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