Mercurial > dropbear
comparison libtomcrypt/src/pk/ecc/ecc_sys.c @ 302:973fccb59ea4 ucc-axis-hack
propagate from branch 'au.asn.ucc.matt.dropbear' (head 11034278bd1917bebcbdc69cf53b1891ce9db121)
to branch 'au.asn.ucc.matt.dropbear.ucc-axis-hack' (head 10a1f614fec73d0820c3f61160d9db409b9beb46)
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Sat, 25 Mar 2006 12:59:58 +0000 |
parents | 1b9e69c058d2 |
children |
comparison
equal
deleted
inserted
replaced
299:740e782679be | 302:973fccb59ea4 |
---|---|
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 | |
12 /** | |
13 @file ecc_sys.c | |
14 ECC Crypto, Tom St Denis | |
15 */ | |
16 | |
17 /** | |
18 Encrypt a symmetric key with ECC | |
19 @param in The symmetric key you want to encrypt | |
20 @param inlen The length of the key to encrypt (octets) | |
21 @param out [out] The destination for the ciphertext | |
22 @param outlen [in/out] The max size and resulting size of the ciphertext | |
23 @param prng An active PRNG state | |
24 @param wprng The index of the PRNG you wish to use | |
25 @param hash The index of the hash you want to use | |
26 @param key The ECC key you want to encrypt to | |
27 @return CRYPT_OK if successful | |
28 */ | |
29 int ecc_encrypt_key(const unsigned char *in, unsigned long inlen, | |
30 unsigned char *out, unsigned long *outlen, | |
31 prng_state *prng, int wprng, int hash, | |
32 ecc_key *key) | |
33 { | |
34 unsigned char *pub_expt, *ecc_shared, *skey; | |
35 ecc_key pubkey; | |
36 unsigned long x, y, pubkeysize; | |
37 int err; | |
38 | |
39 LTC_ARGCHK(in != NULL); | |
40 LTC_ARGCHK(out != NULL); | |
41 LTC_ARGCHK(outlen != NULL); | |
42 LTC_ARGCHK(key != NULL); | |
43 | |
44 /* check that wprng/cipher/hash are not invalid */ | |
45 if ((err = prng_is_valid(wprng)) != CRYPT_OK) { | |
46 return err; | |
47 } | |
48 | |
49 if ((err = hash_is_valid(hash)) != CRYPT_OK) { | |
50 return err; | |
51 } | |
52 | |
53 if (inlen > hash_descriptor[hash].hashsize) { | |
54 return CRYPT_INVALID_HASH; | |
55 } | |
56 | |
57 /* make a random key and export the public copy */ | |
58 if ((err = ecc_make_key(prng, wprng, ecc_get_size(key), &pubkey)) != CRYPT_OK) { | |
59 return err; | |
60 } | |
61 | |
62 pub_expt = XMALLOC(ECC_BUF_SIZE); | |
63 ecc_shared = XMALLOC(ECC_BUF_SIZE); | |
64 skey = XMALLOC(MAXBLOCKSIZE); | |
65 if (pub_expt == NULL || ecc_shared == NULL || skey == NULL) { | |
66 if (pub_expt != NULL) { | |
67 XFREE(pub_expt); | |
68 } | |
69 if (ecc_shared != NULL) { | |
70 XFREE(ecc_shared); | |
71 } | |
72 if (skey != NULL) { | |
73 XFREE(skey); | |
74 } | |
75 ecc_free(&pubkey); | |
76 return CRYPT_MEM; | |
77 } | |
78 | |
79 pubkeysize = ECC_BUF_SIZE; | |
80 if ((err = ecc_export(pub_expt, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) { | |
81 ecc_free(&pubkey); | |
82 goto LBL_ERR; | |
83 } | |
84 | |
85 /* make random key */ | |
86 x = ECC_BUF_SIZE; | |
87 if ((err = ecc_shared_secret(&pubkey, key, ecc_shared, &x)) != CRYPT_OK) { | |
88 ecc_free(&pubkey); | |
89 goto LBL_ERR; | |
90 } | |
91 ecc_free(&pubkey); | |
92 y = MAXBLOCKSIZE; | |
93 if ((err = hash_memory(hash, ecc_shared, x, skey, &y)) != CRYPT_OK) { | |
94 goto LBL_ERR; | |
95 } | |
96 | |
97 /* Encrypt key */ | |
98 for (x = 0; x < inlen; x++) { | |
99 skey[x] ^= in[x]; | |
100 } | |
101 | |
102 err = der_encode_sequence_multi(out, outlen, | |
103 LTC_ASN1_OBJECT_IDENTIFIER, hash_descriptor[hash].OIDlen, hash_descriptor[hash].OID, | |
104 LTC_ASN1_OCTET_STRING, pubkeysize, pub_expt, | |
105 LTC_ASN1_OCTET_STRING, inlen, skey, | |
106 LTC_ASN1_EOL, 0UL, NULL); | |
107 | |
108 LBL_ERR: | |
109 #ifdef LTC_CLEAN_STACK | |
110 /* clean up */ | |
111 zeromem(pub_expt, ECC_BUF_SIZE); | |
112 zeromem(ecc_shared, ECC_BUF_SIZE); | |
113 zeromem(skey, MAXBLOCKSIZE); | |
114 #endif | |
115 | |
116 XFREE(skey); | |
117 XFREE(ecc_shared); | |
118 XFREE(pub_expt); | |
119 | |
120 return err; | |
121 } | |
122 | |
123 /** | |
124 Decrypt an ECC encrypted key | |
125 @param in The ciphertext | |
126 @param inlen The length of the ciphertext (octets) | |
127 @param out [out] The plaintext | |
128 @param outlen [in/out] The max size and resulting size of the plaintext | |
129 @param key The corresponding private ECC key | |
130 @return CRYPT_OK if successful | |
131 */ | |
132 int ecc_decrypt_key(const unsigned char *in, unsigned long inlen, | |
133 unsigned char *out, unsigned long *outlen, | |
134 ecc_key *key) | |
135 { | |
136 unsigned char *ecc_shared, *skey, *pub_expt; | |
137 unsigned long x, y, hashOID[32]; | |
138 int hash, err; | |
139 ecc_key pubkey; | |
140 ltc_asn1_list decode[3]; | |
141 | |
142 LTC_ARGCHK(in != NULL); | |
143 LTC_ARGCHK(out != NULL); | |
144 LTC_ARGCHK(outlen != NULL); | |
145 LTC_ARGCHK(key != NULL); | |
146 | |
147 /* right key type? */ | |
148 if (key->type != PK_PRIVATE) { | |
149 return CRYPT_PK_NOT_PRIVATE; | |
150 } | |
151 | |
152 /* decode to find out hash */ | |
153 LTC_SET_ASN1(decode, 0, LTC_ASN1_OBJECT_IDENTIFIER, hashOID, sizeof(hashOID)/sizeof(hashOID[0])); | |
154 | |
155 if ((err = der_decode_sequence(in, inlen, decode, 1)) != CRYPT_OK) { | |
156 return err; | |
157 } | |
158 for (hash = 0; hash_descriptor[hash].name != NULL && | |
159 (hash_descriptor[hash].OIDlen != decode[0].size || | |
160 memcmp(hash_descriptor[hash].OID, hashOID, sizeof(unsigned long)*decode[0].size)); hash++); | |
161 | |
162 if (hash_descriptor[hash].name == NULL) { | |
163 return CRYPT_INVALID_PACKET; | |
164 } | |
165 | |
166 /* we now have the hash! */ | |
167 | |
168 /* allocate memory */ | |
169 pub_expt = XMALLOC(ECC_BUF_SIZE); | |
170 ecc_shared = XMALLOC(ECC_BUF_SIZE); | |
171 skey = XMALLOC(MAXBLOCKSIZE); | |
172 if (pub_expt == NULL || ecc_shared == NULL || skey == NULL) { | |
173 if (pub_expt != NULL) { | |
174 XFREE(pub_expt); | |
175 } | |
176 if (ecc_shared != NULL) { | |
177 XFREE(ecc_shared); | |
178 } | |
179 if (skey != NULL) { | |
180 XFREE(skey); | |
181 } | |
182 return CRYPT_MEM; | |
183 } | |
184 LTC_SET_ASN1(decode, 1, LTC_ASN1_OCTET_STRING, pub_expt, ECC_BUF_SIZE); | |
185 LTC_SET_ASN1(decode, 2, LTC_ASN1_OCTET_STRING, skey, MAXBLOCKSIZE); | |
186 | |
187 /* read the structure in now */ | |
188 if ((err = der_decode_sequence(in, inlen, decode, 3)) != CRYPT_OK) { | |
189 goto LBL_ERR; | |
190 } | |
191 | |
192 /* import ECC key from packet */ | |
193 if ((err = ecc_import(decode[1].data, decode[1].size, &pubkey)) != CRYPT_OK) { | |
194 goto LBL_ERR; | |
195 } | |
196 | |
197 /* make shared key */ | |
198 x = ECC_BUF_SIZE; | |
199 if ((err = ecc_shared_secret(key, &pubkey, ecc_shared, &x)) != CRYPT_OK) { | |
200 ecc_free(&pubkey); | |
201 goto LBL_ERR; | |
202 } | |
203 ecc_free(&pubkey); | |
204 | |
205 y = MAXBLOCKSIZE; | |
206 if ((err = hash_memory(hash, ecc_shared, x, ecc_shared, &y)) != CRYPT_OK) { | |
207 goto LBL_ERR; | |
208 } | |
209 | |
210 /* ensure the hash of the shared secret is at least as big as the encrypt itself */ | |
211 if (decode[2].size > y) { | |
212 err = CRYPT_INVALID_PACKET; | |
213 goto LBL_ERR; | |
214 } | |
215 | |
216 /* avoid buffer overflow */ | |
217 if (*outlen < decode[2].size) { | |
218 err = CRYPT_BUFFER_OVERFLOW; | |
219 goto LBL_ERR; | |
220 } | |
221 | |
222 /* Decrypt the key */ | |
223 for (x = 0; x < decode[2].size; x++) { | |
224 out[x] = skey[x] ^ ecc_shared[x]; | |
225 } | |
226 *outlen = x; | |
227 | |
228 err = CRYPT_OK; | |
229 LBL_ERR: | |
230 #ifdef LTC_CLEAN_STACK | |
231 zeromem(pub_expt, ECC_BUF_SIZE); | |
232 zeromem(ecc_shared, ECC_BUF_SIZE); | |
233 zeromem(skey, MAXBLOCKSIZE); | |
234 #endif | |
235 | |
236 XFREE(pub_expt); | |
237 XFREE(ecc_shared); | |
238 XFREE(skey); | |
239 | |
240 return err; | |
241 } | |
242 | |
243 /** | |
244 Sign a message digest | |
245 @param in The message digest to sign | |
246 @param inlen The length of the digest | |
247 @param out [out] The destination for the signature | |
248 @param outlen [in/out] The max size and resulting size of the signature | |
249 @param prng An active PRNG state | |
250 @param wprng The index of the PRNG you wish to use | |
251 @param key A private ECC key | |
252 @return CRYPT_OK if successful | |
253 */ | |
254 int ecc_sign_hash(const unsigned char *in, unsigned long inlen, | |
255 unsigned char *out, unsigned long *outlen, | |
256 prng_state *prng, int wprng, ecc_key *key) | |
257 { | |
258 ecc_key pubkey; | |
259 mp_int r, s, e, p; | |
260 int err; | |
261 | |
262 LTC_ARGCHK(in != NULL); | |
263 LTC_ARGCHK(out != NULL); | |
264 LTC_ARGCHK(outlen != NULL); | |
265 LTC_ARGCHK(key != NULL); | |
266 | |
267 /* is this a private key? */ | |
268 if (key->type != PK_PRIVATE) { | |
269 return CRYPT_PK_NOT_PRIVATE; | |
270 } | |
271 | |
272 /* is the IDX valid ? */ | |
273 if (is_valid_idx(key->idx) != 1) { | |
274 return CRYPT_PK_INVALID_TYPE; | |
275 } | |
276 | |
277 if ((err = prng_is_valid(wprng)) != CRYPT_OK) { | |
278 return err; | |
279 } | |
280 | |
281 /* get the hash and load it as a bignum into 'e' */ | |
282 /* init the bignums */ | |
283 if ((err = mp_init_multi(&r, &s, &p, &e, NULL)) != MP_OKAY) { | |
284 ecc_free(&pubkey); | |
285 err = mpi_to_ltc_error(err); | |
286 goto LBL_ERR; | |
287 } | |
288 if ((err = mp_read_radix(&p, (char *)sets[key->idx].order, 64)) != MP_OKAY) { goto error; } | |
289 if ((err = mp_read_unsigned_bin(&e, (unsigned char *)in, (int)inlen)) != MP_OKAY) { goto error; } | |
290 | |
291 /* make up a key and export the public copy */ | |
292 for (;;) { | |
293 if ((err = ecc_make_key(prng, wprng, ecc_get_size(key), &pubkey)) != CRYPT_OK) { | |
294 return err; | |
295 } | |
296 | |
297 /* find r = x1 mod n */ | |
298 if ((err = mp_mod(&pubkey.pubkey.x, &p, &r)) != MP_OKAY) { goto error; } | |
299 | |
300 if (mp_iszero(&r)) { | |
301 ecc_free(&pubkey); | |
302 } else { | |
303 /* find s = (e + xr)/k */ | |
304 if ((err = mp_invmod(&pubkey.k, &p, &pubkey.k)) != MP_OKAY) { goto error; } /* k = 1/k */ | |
305 if ((err = mp_mulmod(&key->k, &r, &p, &s)) != MP_OKAY) { goto error; } /* s = xr */ | |
306 if ((err = mp_addmod(&e, &s, &p, &s)) != MP_OKAY) { goto error; } /* s = e + xr */ | |
307 if ((err = mp_mulmod(&s, &pubkey.k, &p, &s)) != MP_OKAY) { goto error; } /* s = (e + xr)/k */ | |
308 | |
309 if (mp_iszero(&s)) { | |
310 ecc_free(&pubkey); | |
311 } else { | |
312 break; | |
313 } | |
314 } | |
315 } | |
316 | |
317 /* store as SEQUENCE { r, s -- integer } */ | |
318 err = der_encode_sequence_multi(out, outlen, | |
319 LTC_ASN1_INTEGER, 1UL, &r, | |
320 LTC_ASN1_INTEGER, 1UL, &s, | |
321 LTC_ASN1_EOL, 0UL, NULL); | |
322 goto LBL_ERR; | |
323 error: | |
324 err = mpi_to_ltc_error(err); | |
325 LBL_ERR: | |
326 mp_clear_multi(&r, &s, &p, &e, NULL); | |
327 ecc_free(&pubkey); | |
328 | |
329 return err; | |
330 } | |
331 | |
332 /* verify | |
333 * | |
334 * w = s^-1 mod n | |
335 * u1 = xw | |
336 * u2 = rw | |
337 * X = u1*G + u2*Q | |
338 * v = X_x1 mod n | |
339 * accept if v == r | |
340 */ | |
341 | |
342 /** | |
343 Verify an ECC signature | |
344 @param sig The signature to verify | |
345 @param siglen The length of the signature (octets) | |
346 @param hash The hash (message digest) that was signed | |
347 @param hashlen The length of the hash (octets) | |
348 @param stat Result of signature, 1==valid, 0==invalid | |
349 @param key The corresponding public ECC key | |
350 @return CRYPT_OK if successful (even if the signature is not valid) | |
351 */ | |
352 int ecc_verify_hash(const unsigned char *sig, unsigned long siglen, | |
353 const unsigned char *hash, unsigned long hashlen, | |
354 int *stat, ecc_key *key) | |
355 { | |
356 ecc_point *mG, *mQ; | |
357 mp_int r, s, v, w, u1, u2, e, p, m; | |
358 mp_digit mp; | |
359 int err; | |
360 | |
361 LTC_ARGCHK(sig != NULL); | |
362 LTC_ARGCHK(hash != NULL); | |
363 LTC_ARGCHK(stat != NULL); | |
364 LTC_ARGCHK(key != NULL); | |
365 | |
366 /* default to invalid signature */ | |
367 *stat = 0; | |
368 | |
369 /* is the IDX valid ? */ | |
370 if (is_valid_idx(key->idx) != 1) { | |
371 return CRYPT_PK_INVALID_TYPE; | |
372 } | |
373 | |
374 /* allocate ints */ | |
375 if ((err = mp_init_multi(&r, &s, &v, &w, &u1, &u2, &p, &e, &m, NULL)) != MP_OKAY) { | |
376 return CRYPT_MEM; | |
377 } | |
378 | |
379 /* allocate points */ | |
380 mG = new_point(); | |
381 mQ = new_point(); | |
382 if (mQ == NULL || mG == NULL) { | |
383 err = CRYPT_MEM; | |
384 goto done; | |
385 } | |
386 | |
387 /* parse header */ | |
388 if ((err = der_decode_sequence_multi(sig, siglen, | |
389 LTC_ASN1_INTEGER, 1UL, &r, | |
390 LTC_ASN1_INTEGER, 1UL, &s, | |
391 LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { | |
392 goto done; | |
393 } | |
394 | |
395 /* get the order */ | |
396 if ((err = mp_read_radix(&p, (char *)sets[key->idx].order, 64)) != MP_OKAY) { goto error; } | |
397 | |
398 /* get the modulus */ | |
399 if ((err = mp_read_radix(&m, (char *)sets[key->idx].prime, 64)) != MP_OKAY) { goto error; } | |
400 | |
401 /* check for zero */ | |
402 if (mp_iszero(&r) || mp_iszero(&s) || mp_cmp(&r, &p) != MP_LT || mp_cmp(&s, &p) != MP_LT) { | |
403 err = CRYPT_INVALID_PACKET; | |
404 goto done; | |
405 } | |
406 | |
407 /* read hash */ | |
408 if ((err = mp_read_unsigned_bin(&e, (unsigned char *)hash, (int)hashlen)) != MP_OKAY) { goto error; } | |
409 | |
410 /* w = s^-1 mod n */ | |
411 if ((err = mp_invmod(&s, &p, &w)) != MP_OKAY) { goto error; } | |
412 | |
413 /* u1 = ew */ | |
414 if ((err = mp_mulmod(&e, &w, &p, &u1)) != MP_OKAY) { goto error; } | |
415 | |
416 /* u2 = rw */ | |
417 if ((err = mp_mulmod(&r, &w, &p, &u2)) != MP_OKAY) { goto error; } | |
418 | |
419 /* find mG = u1*G */ | |
420 if ((err = mp_read_radix(&mG->x, (char *)sets[key->idx].Gx, 64)) != MP_OKAY) { goto error; } | |
421 if ((err = mp_read_radix(&mG->y, (char *)sets[key->idx].Gy, 64)) != MP_OKAY) { goto error; } | |
422 mp_set(&mG->z, 1); | |
423 if ((err = ecc_mulmod(&u1, mG, mG, &m, 0)) != CRYPT_OK) { goto done; } | |
424 | |
425 /* find mQ = u2*Q */ | |
426 if ((err = mp_copy(&key->pubkey.x, &mQ->x)) != MP_OKAY) { goto error; } | |
427 if ((err = mp_copy(&key->pubkey.y, &mQ->y)) != MP_OKAY) { goto error; } | |
428 if ((err = mp_copy(&key->pubkey.z, &mQ->z)) != MP_OKAY) { goto error; } | |
429 if ((err = ecc_mulmod(&u2, mQ, mQ, &m, 0)) != CRYPT_OK) { goto done; } | |
430 | |
431 /* find the montgomery mp */ | |
432 if ((err = mp_montgomery_setup(&m, &mp)) != MP_OKAY) { goto error; } | |
433 /* add them */ | |
434 if ((err = add_point(mQ, mG, mG, &m, mp)) != CRYPT_OK) { goto done; } | |
435 | |
436 /* reduce */ | |
437 if ((err = ecc_map(mG, &m, mp)) != CRYPT_OK) { goto done; } | |
438 | |
439 /* v = X_x1 mod n */ | |
440 if ((err = mp_mod(&mG->x, &p, &v)) != CRYPT_OK) { goto done; } | |
441 | |
442 /* does v == r */ | |
443 if (mp_cmp(&v, &r) == MP_EQ) { | |
444 *stat = 1; | |
445 } | |
446 | |
447 /* clear up and return */ | |
448 err = CRYPT_OK; | |
449 goto done; | |
450 error: | |
451 err = mpi_to_ltc_error(err); | |
452 done: | |
453 del_point(mG); | |
454 del_point(mQ); | |
455 mp_clear_multi(&r, &s, &v, &w, &u1, &u2, &p, &e, &m, NULL); | |
456 return err; | |
457 } | |
458 | |
459 | |
460 /* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ecc_sys.c,v $ */ | |
461 /* $Revision: 1.18 $ */ | |
462 /* $Date: 2005/06/14 20:47:55 $ */ |