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 $ */