/** Decrypt an DSA encrypted key @param in The ciphertext @param inlen The length of the ciphertext (octets) @param out [out] The plaintext @param outlen [in/out] The max size and resulting size of the plaintext @param key The corresponding private DSA key @return CRYPT_OK if successful */ int dsa_decrypt_key(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, dsa_key *key) { unsigned char *skey, *expt; void *g_pub; unsigned long x, y, hashOID[32]; int hash, err; ltc_asn1_list decode[3]; LTC_ARGCHK(in != NULL); LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); LTC_ARGCHK(key != NULL); /* right key type? */ if (key->type != PK_PRIVATE) { return CRYPT_PK_NOT_PRIVATE; } /* decode to find out hash */ LTC_SET_ASN1(decode, 0, LTC_ASN1_OBJECT_IDENTIFIER, hashOID, sizeof(hashOID)/sizeof(hashOID[0])); if ((err = der_decode_sequence(in, inlen, decode, 1)) != CRYPT_OK) { return err; } hash = find_hash_oid(hashOID, decode[0].size); if (hash_is_valid(hash) != CRYPT_OK) { return CRYPT_INVALID_PACKET; } /* we now have the hash! */ if ((err = mp_init(&g_pub)) != CRYPT_OK) { return err; } /* allocate memory */ expt = XMALLOC(mp_unsigned_bin_size(key->p) + 1); skey = XMALLOC(MAXBLOCKSIZE); if (expt == NULL || skey == NULL) { if (expt != NULL) { XFREE(expt); } if (skey != NULL) { XFREE(skey); } mp_clear(g_pub); return CRYPT_MEM; } LTC_SET_ASN1(decode, 1, LTC_ASN1_INTEGER, g_pub, 1UL); LTC_SET_ASN1(decode, 2, LTC_ASN1_OCTET_STRING, skey, MAXBLOCKSIZE); /* read the structure in now */ if ((err = der_decode_sequence(in, inlen, decode, 3)) != CRYPT_OK) { goto LBL_ERR; } /* make shared key */ x = mp_unsigned_bin_size(key->p) + 1; if ((err = dsa_shared_secret(key->x, g_pub, key, expt, &x)) != CRYPT_OK) { goto LBL_ERR; } y = MIN(mp_unsigned_bin_size(key->p) + 1, MAXBLOCKSIZE); if ((err = hash_memory(hash, expt, x, expt, &y)) != CRYPT_OK) { goto LBL_ERR; } /* ensure the hash of the shared secret is at least as big as the encrypt itself */ if (decode[2].size > y) { err = CRYPT_INVALID_PACKET; goto LBL_ERR; } /* avoid buffer overflow */ if (*outlen < decode[2].size) { *outlen = decode[2].size; err = CRYPT_BUFFER_OVERFLOW; goto LBL_ERR; } /* Decrypt the key */ for (x = 0; x < decode[2].size; x++) { out[x] = expt[x] ^ skey[x]; } *outlen = x; err = CRYPT_OK; LBL_ERR: #ifdef LTC_CLEAN_STACK zeromem(expt, mp_unsigned_bin_size(key->p) + 1); zeromem(skey, MAXBLOCKSIZE); #endif XFREE(expt); XFREE(skey); mp_clear(g_pub); return err; }
/** Decrypt an ECC encrypted key @param in The ciphertext @param inlen The length of the ciphertext (octets) @param out [out] The plaintext @param outlen [in/out] The max size and resulting size of the plaintext @param key The corresponding private ECC key @return CRYPT_OK if successful */ int ecc_decrypt_key(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, ecc_key *key) { unsigned char *ecc_shared, *skey, *pub_expt; unsigned long x, y; unsigned long hashOID[32] = { 0 }; int hash, err; ecc_key pubkey; ltc_asn1_list decode[3]; LTC_ARGCHK(in != NULL); LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); LTC_ARGCHK(key != NULL); /* right key type? */ if (key->type != PK_PRIVATE) { return CRYPT_PK_NOT_PRIVATE; } /* decode to find out hash */ LTC_SET_ASN1(decode, 0, LTC_ASN1_OBJECT_IDENTIFIER, hashOID, sizeof(hashOID)/sizeof(hashOID[0])); err = der_decode_sequence(in, inlen, decode, 1); if (err != CRYPT_OK && err != CRYPT_INPUT_TOO_LONG) { return err; } hash = find_hash_oid(hashOID, decode[0].size); if (hash_is_valid(hash) != CRYPT_OK) { return CRYPT_INVALID_PACKET; } /* we now have the hash! */ /* allocate memory */ pub_expt = XMALLOC(ECC_BUF_SIZE); ecc_shared = XMALLOC(ECC_BUF_SIZE); skey = XMALLOC(MAXBLOCKSIZE); if (pub_expt == NULL || ecc_shared == NULL || skey == NULL) { if (pub_expt != NULL) { XFREE(pub_expt); } if (ecc_shared != NULL) { XFREE(ecc_shared); } if (skey != NULL) { XFREE(skey); } return CRYPT_MEM; } LTC_SET_ASN1(decode, 1, LTC_ASN1_OCTET_STRING, pub_expt, ECC_BUF_SIZE); LTC_SET_ASN1(decode, 2, LTC_ASN1_OCTET_STRING, skey, MAXBLOCKSIZE); /* read the structure in now */ if ((err = der_decode_sequence(in, inlen, decode, 3)) != CRYPT_OK) { goto LBL_ERR; } /* import ECC key from packet */ if ((err = ecc_import(decode[1].data, decode[1].size, &pubkey)) != CRYPT_OK) { goto LBL_ERR; } /* make shared key */ x = ECC_BUF_SIZE; if ((err = ecc_shared_secret(key, &pubkey, ecc_shared, &x)) != CRYPT_OK) { ecc_free(&pubkey); goto LBL_ERR; } ecc_free(&pubkey); y = MIN(ECC_BUF_SIZE, MAXBLOCKSIZE); if ((err = hash_memory(hash, ecc_shared, x, ecc_shared, &y)) != CRYPT_OK) { goto LBL_ERR; } /* ensure the hash of the shared secret is at least as big as the encrypt itself */ if (decode[2].size > y) { err = CRYPT_INVALID_PACKET; goto LBL_ERR; } /* avoid buffer overflow */ if (*outlen < decode[2].size) { *outlen = decode[2].size; err = CRYPT_BUFFER_OVERFLOW; goto LBL_ERR; } /* Decrypt the key */ for (x = 0; x < decode[2].size; x++) { out[x] = skey[x] ^ ecc_shared[x]; } *outlen = x; err = CRYPT_OK; LBL_ERR: #ifdef LTC_CLEAN_STACK zeromem(pub_expt, ECC_BUF_SIZE); zeromem(ecc_shared, ECC_BUF_SIZE); zeromem(skey, MAXBLOCKSIZE); #endif XFREE(pub_expt); XFREE(ecc_shared); XFREE(skey); return err; }