1
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
3
* LibTomCrypt is a library that provides various cryptographic
4
* algorithms in a highly modular and flexible manner.
6
* The library is free for all purposes without any express
9
* Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.org
14
ECC Crypto, Tom St Denis
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
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,
34
unsigned char *pub_expt, *ecc_shared, *skey;
36
unsigned long x, y, pubkeysize;
39
LTC_ARGCHK(in != NULL);
40
LTC_ARGCHK(out != NULL);
41
LTC_ARGCHK(outlen != NULL);
42
LTC_ARGCHK(key != NULL);
44
/* check that wprng/cipher/hash are not invalid */
45
if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
49
if ((err = hash_is_valid(hash)) != CRYPT_OK) {
53
if (inlen > hash_descriptor[hash].hashsize) {
54
return CRYPT_INVALID_HASH;
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) {
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) {
69
if (ecc_shared != NULL) {
79
pubkeysize = ECC_BUF_SIZE;
80
if ((err = ecc_export(pub_expt, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) {
87
if ((err = ecc_shared_secret(&pubkey, key, ecc_shared, &x)) != CRYPT_OK) {
93
if ((err = hash_memory(hash, ecc_shared, x, skey, &y)) != CRYPT_OK) {
98
for (x = 0; x < inlen; x++) {
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);
109
#ifdef LTC_CLEAN_STACK
111
zeromem(pub_expt, ECC_BUF_SIZE);
112
zeromem(ecc_shared, ECC_BUF_SIZE);
113
zeromem(skey, MAXBLOCKSIZE);
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
132
int ecc_decrypt_key(const unsigned char *in, unsigned long inlen,
133
unsigned char *out, unsigned long *outlen,
136
unsigned char *ecc_shared, *skey, *pub_expt;
137
unsigned long x, y, hashOID[32];
140
ltc_asn1_list decode[3];
142
LTC_ARGCHK(in != NULL);
143
LTC_ARGCHK(out != NULL);
144
LTC_ARGCHK(outlen != NULL);
145
LTC_ARGCHK(key != NULL);
147
/* right key type? */
148
if (key->type != PK_PRIVATE) {
149
return CRYPT_PK_NOT_PRIVATE;
152
/* decode to find out hash */
153
LTC_SET_ASN1(decode, 0, LTC_ASN1_OBJECT_IDENTIFIER, hashOID, sizeof(hashOID)/sizeof(hashOID[0]));
155
if ((err = der_decode_sequence(in, inlen, decode, 1)) != CRYPT_OK) {
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++);
162
if (hash_descriptor[hash].name == NULL) {
163
return CRYPT_INVALID_PACKET;
166
/* we now have the hash! */
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) {
176
if (ecc_shared != NULL) {
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);
187
/* read the structure in now */
188
if ((err = der_decode_sequence(in, inlen, decode, 3)) != CRYPT_OK) {
192
/* import ECC key from packet */
193
if ((err = ecc_import(decode[1].data, decode[1].size, &pubkey)) != CRYPT_OK) {
197
/* make shared key */
199
if ((err = ecc_shared_secret(key, &pubkey, ecc_shared, &x)) != CRYPT_OK) {
206
if ((err = hash_memory(hash, ecc_shared, x, ecc_shared, &y)) != CRYPT_OK) {
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;
216
/* avoid buffer overflow */
217
if (*outlen < decode[2].size) {
218
err = CRYPT_BUFFER_OVERFLOW;
222
/* Decrypt the key */
223
for (x = 0; x < decode[2].size; x++) {
224
out[x] = skey[x] ^ ecc_shared[x];
230
#ifdef LTC_CLEAN_STACK
231
zeromem(pub_expt, ECC_BUF_SIZE);
232
zeromem(ecc_shared, ECC_BUF_SIZE);
233
zeromem(skey, MAXBLOCKSIZE);
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
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)
262
LTC_ARGCHK(in != NULL);
263
LTC_ARGCHK(out != NULL);
264
LTC_ARGCHK(outlen != NULL);
265
LTC_ARGCHK(key != NULL);
267
/* is this a private key? */
268
if (key->type != PK_PRIVATE) {
269
return CRYPT_PK_NOT_PRIVATE;
272
/* is the IDX valid ? */
273
if (is_valid_idx(key->idx) != 1) {
274
return CRYPT_PK_INVALID_TYPE;
277
if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
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) {
285
err = mpi_to_ltc_error(err);
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; }
291
/* make up a key and export the public copy */
293
if ((err = ecc_make_key(prng, wprng, ecc_get_size(key), &pubkey)) != CRYPT_OK) {
297
/* find r = x1 mod n */
298
if ((err = mp_mod(&pubkey.pubkey.x, &p, &r)) != MP_OKAY) { goto error; }
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 */
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);
324
err = mpi_to_ltc_error(err);
326
mp_clear_multi(&r, &s, &p, &e, NULL);
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)
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)
357
mp_int r, s, v, w, u1, u2, e, p, m;
361
LTC_ARGCHK(sig != NULL);
362
LTC_ARGCHK(hash != NULL);
363
LTC_ARGCHK(stat != NULL);
364
LTC_ARGCHK(key != NULL);
366
/* default to invalid signature */
369
/* is the IDX valid ? */
370
if (is_valid_idx(key->idx) != 1) {
371
return CRYPT_PK_INVALID_TYPE;
375
if ((err = mp_init_multi(&r, &s, &v, &w, &u1, &u2, &p, &e, &m, NULL)) != MP_OKAY) {
379
/* allocate points */
382
if (mQ == NULL || mG == NULL) {
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) {
396
if ((err = mp_read_radix(&p, (char *)sets[key->idx].order, 64)) != MP_OKAY) { goto error; }
398
/* get the modulus */
399
if ((err = mp_read_radix(&m, (char *)sets[key->idx].prime, 64)) != MP_OKAY) { goto error; }
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;
408
if ((err = mp_read_unsigned_bin(&e, (unsigned char *)hash, (int)hashlen)) != MP_OKAY) { goto error; }
411
if ((err = mp_invmod(&s, &p, &w)) != MP_OKAY) { goto error; }
414
if ((err = mp_mulmod(&e, &w, &p, &u1)) != MP_OKAY) { goto error; }
417
if ((err = mp_mulmod(&r, &w, &p, &u2)) != MP_OKAY) { goto error; }
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; }
423
if ((err = ecc_mulmod(&u1, mG, mG, &m, 0)) != CRYPT_OK) { goto done; }
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; }
431
/* find the montgomery mp */
432
if ((err = mp_montgomery_setup(&m, &mp)) != MP_OKAY) { goto error; }
434
if ((err = add_point(mQ, mG, mG, &m, mp)) != CRYPT_OK) { goto done; }
437
if ((err = ecc_map(mG, &m, mp)) != CRYPT_OK) { goto done; }
440
if ((err = mp_mod(&mG->x, &p, &v)) != CRYPT_OK) { goto done; }
443
if (mp_cmp(&v, &r) == MP_EQ) {
447
/* clear up and return */
451
err = mpi_to_ltc_error(err);
455
mp_clear_multi(&r, &s, &v, &w, &u1, &u2, &p, &e, &m, NULL);
460
/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ecc_sys.c,v $ */
461
/* $Revision: 1.18 $ */
462
/* $Date: 2005/06/14 20:47:55 $ */