1 // SPDX-License-Identifier: BSD-2-Clause
2 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
3 *
4 * LibTomCrypt is a library that provides various cryptographic
5 * algorithms in a highly modular and flexible manner.
6 *
7 * The library is free for all purposes without any express
8 * guarantee it works.
9 */
10
11 #include "tomcrypt_private.h"
12
13 /**
14 @file ecc_decrypt_key.c
15 ECC Crypto, Tom St Denis
16 */
17
18 #ifdef LTC_MECC
19
20 /**
21 Decrypt an ECC encrypted key
22 @param in The ciphertext
23 @param inlen The length of the ciphertext (octets)
24 @param out [out] The plaintext
25 @param outlen [in/out] The max size and resulting size of the plaintext
26 @param key The corresponding private ECC key
27 @return CRYPT_OK if successful
28 */
ecc_decrypt_key(const unsigned char * in,unsigned long inlen,unsigned char * out,unsigned long * outlen,const ecc_key * key)29 int ecc_decrypt_key(const unsigned char *in, unsigned long inlen,
30 unsigned char *out, unsigned long *outlen,
31 const ecc_key *key)
32 {
33 unsigned char *ecc_shared, *skey, *pub_expt;
34 unsigned long x, y;
35 unsigned long hashOID[32] = { 0 };
36 int hash, err;
37 ecc_key pubkey;
38 ltc_asn1_list decode[3];
39
40 LTC_ARGCHK(in != NULL);
41 LTC_ARGCHK(out != NULL);
42 LTC_ARGCHK(outlen != NULL);
43 LTC_ARGCHK(key != NULL);
44
45 /* right key type? */
46 if (key->type != PK_PRIVATE) {
47 return CRYPT_PK_NOT_PRIVATE;
48 }
49
50 /* decode to find out hash */
51 LTC_SET_ASN1(decode, 0, LTC_ASN1_OBJECT_IDENTIFIER, hashOID, sizeof(hashOID)/sizeof(hashOID[0]));
52 err = der_decode_sequence(in, inlen, decode, 1);
53 if (err != CRYPT_OK && err != CRYPT_INPUT_TOO_LONG) {
54 return err;
55 }
56
57 hash = find_hash_oid(hashOID, decode[0].size);
58 if (hash_is_valid(hash) != CRYPT_OK) {
59 return CRYPT_INVALID_PACKET;
60 }
61
62 /* we now have the hash! */
63
64 /* allocate memory */
65 pub_expt = XMALLOC(ECC_BUF_SIZE);
66 ecc_shared = XMALLOC(ECC_BUF_SIZE);
67 skey = XMALLOC(MAXBLOCKSIZE);
68 if (pub_expt == NULL || ecc_shared == NULL || skey == NULL) {
69 if (pub_expt != NULL) {
70 XFREE(pub_expt);
71 }
72 if (ecc_shared != NULL) {
73 XFREE(ecc_shared);
74 }
75 if (skey != NULL) {
76 XFREE(skey);
77 }
78 return CRYPT_MEM;
79 }
80 LTC_SET_ASN1(decode, 1, LTC_ASN1_OCTET_STRING, pub_expt, ECC_BUF_SIZE);
81 LTC_SET_ASN1(decode, 2, LTC_ASN1_OCTET_STRING, skey, MAXBLOCKSIZE);
82
83 /* read the structure in now */
84 if ((err = der_decode_sequence(in, inlen, decode, 3)) != CRYPT_OK) {
85 goto LBL_ERR;
86 }
87
88 /* import ECC key from packet */
89 if ((err = ecc_copy_curve(key, &pubkey)) != CRYPT_OK) { goto LBL_ERR; }
90 if ((err = ecc_set_key(decode[1].data, decode[1].size, PK_PUBLIC, &pubkey)) != CRYPT_OK) { goto LBL_ERR; }
91
92 /* make shared key */
93 x = ECC_BUF_SIZE;
94 if ((err = ecc_shared_secret(key, &pubkey, ecc_shared, &x)) != CRYPT_OK) {
95 ecc_free(&pubkey);
96 goto LBL_ERR;
97 }
98 ecc_free(&pubkey);
99
100 y = MIN(ECC_BUF_SIZE, MAXBLOCKSIZE);
101 if ((err = hash_memory(hash, ecc_shared, x, ecc_shared, &y)) != CRYPT_OK) {
102 goto LBL_ERR;
103 }
104
105 /* ensure the hash of the shared secret is at least as big as the encrypt itself */
106 if (decode[2].size > y) {
107 err = CRYPT_INVALID_PACKET;
108 goto LBL_ERR;
109 }
110
111 /* avoid buffer overflow */
112 if (*outlen < decode[2].size) {
113 *outlen = decode[2].size;
114 err = CRYPT_BUFFER_OVERFLOW;
115 goto LBL_ERR;
116 }
117
118 /* Decrypt the key */
119 for (x = 0; x < decode[2].size; x++) {
120 out[x] = skey[x] ^ ecc_shared[x];
121 }
122 *outlen = x;
123
124 err = CRYPT_OK;
125 LBL_ERR:
126 #ifdef LTC_CLEAN_STACK
127 zeromem(pub_expt, ECC_BUF_SIZE);
128 zeromem(ecc_shared, ECC_BUF_SIZE);
129 zeromem(skey, MAXBLOCKSIZE);
130 #endif
131
132 XFREE(pub_expt);
133 XFREE(ecc_shared);
134 XFREE(skey);
135
136 return err;
137 }
138
139 #endif
140
141 /* ref: $Format:%D$ */
142 /* git commit: $Format:%H$ */
143 /* commit time: $Format:%ai$ */
144
145