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