diff --git a/src/lib/crypto/ecdh.cpp b/src/lib/crypto/ecdh.cpp index bee7c12df..66e5f8d1d 100644 --- a/src/lib/crypto/ecdh.cpp +++ b/src/lib/crypto/ecdh.cpp @@ -25,6 +25,7 @@ */ #include +#include #include #include "hash_botan.hpp" #include "ecdh.h" @@ -38,14 +39,13 @@ // Produces kek of size kek_len which corresponds to length of wrapping key static bool -compute_kek(uint8_t * kek, - size_t kek_len, - const uint8_t * other_info, - size_t other_info_size, - const ec_curve_desc_t *curve_desc, - const pgp::mpi * ec_pubkey, - const botan_privkey_t ec_prvkey, - const pgp_hash_alg_t hash_alg) +compute_kek(uint8_t * kek, + size_t kek_len, + const std::vector &other_info, + const ec_curve_desc_t * curve_desc, + const pgp::mpi * ec_pubkey, + const botan_privkey_t ec_prvkey, + const pgp_hash_alg_t hash_alg) { const uint8_t *p = ec_pubkey->mpi; uint8_t p_len = ec_pubkey->len; @@ -73,7 +73,7 @@ compute_kek(uint8_t * kek, snprintf( kdf_name, sizeof(kdf_name), "SP800-56A(%s)", rnp::Hash_Botan::name_backend(hash_alg)); ret = !botan_kdf( - kdf_name, kek, kek_len, s.data(), s_len, NULL, 0, other_info, other_info_size); + kdf_name, kek, kek_len, s.data(), s_len, NULL, 0, other_info.data(), other_info.size()); end: return ret && !botan_pk_op_key_agreement_destroy(op_key_agreement); } @@ -194,7 +194,6 @@ ecdh_encrypt_pkcs5(rnp::RNG * rng, { botan_privkey_t eph_prv_key = NULL; rnp_result_t ret = RNP_ERROR_GENERIC; - uint8_t other_info[MAX_SP800_56A_OTHER_INFO]; uint8_t kek[32] = {0}; // Size of SHA-256 or smaller // 'm' is padded to the 8-byte granularity uint8_t m[MAX_SESSION_KEY_SIZE]; @@ -220,16 +219,11 @@ ecdh_encrypt_pkcs5(rnp::RNG * rng, return RNP_ERROR_BAD_PARAMETERS; } - // See 13.5 of RFC 4880 for definition of other_info_size - const size_t other_info_size = curve_desc->OID.size() + 46; + // See 13.5 of RFC 4880 for definition of other_info size const size_t kek_len = pgp_key_size(key->key_wrap_alg); - size_t tmp_len = kdf_other_info_serialize( - other_info, curve_desc, fingerprint, key->kdf_hash_alg, key->key_wrap_alg); - - if (tmp_len != other_info_size) { - RNP_LOG("Serialization of other info failed"); - return RNP_ERROR_GENERIC; - } + auto other_info = + kdf_other_info_serialize(curve_desc, fingerprint, key->kdf_hash_alg, key->key_wrap_alg); + assert(other_info.size() == curve_desc->OID.size() + 46); if (!strcmp(curve_desc->botan_name, "curve25519")) { if (botan_privkey_create(&eph_prv_key, "Curve25519", "", rng->handle())) { @@ -242,14 +236,8 @@ ecdh_encrypt_pkcs5(rnp::RNG * rng, } } - if (!compute_kek(kek, - kek_len, - other_info, - other_info_size, - curve_desc, - &key->p, - eph_prv_key, - key->kdf_hash_alg)) { + if (!compute_kek( + kek, kek_len, other_info, curve_desc, &key->p, eph_prv_key, key->kdf_hash_alg)) { RNP_LOG("KEK computation failed"); goto end; } @@ -321,15 +309,8 @@ ecdh_decrypt_pkcs5(uint8_t * out, } // See 13.5 of RFC 4880 for definition of other_info_size - uint8_t other_info[MAX_SP800_56A_OTHER_INFO]; - const size_t other_info_size = curve_desc->OID.size() + 46; - const size_t tmp_len = - kdf_other_info_serialize(other_info, curve_desc, fingerprint, kdf_hash, wrap_alg); - - if (other_info_size != tmp_len) { - RNP_LOG("Serialization of other info failed"); - return RNP_ERROR_GENERIC; - } + auto other_info = kdf_other_info_serialize(curve_desc, fingerprint, kdf_hash, wrap_alg); + assert(other_info.size() == curve_desc->OID.size() + 46); botan_privkey_t prv_key = NULL; if (!ecdh_load_secret_key(&prv_key, key)) { @@ -349,14 +330,7 @@ ecdh_decrypt_pkcs5(uint8_t * out, * botan_key_unwrap3394 or unpad_pkcs7 fails */ size_t kek_len = pgp_key_size(wrap_alg); - if (!compute_kek(kek.data(), - kek_len, - other_info, - other_info_size, - curve_desc, - &in->p, - prv_key, - kdf_hash)) { + if (!compute_kek(kek.data(), kek_len, other_info, curve_desc, &in->p, prv_key, kdf_hash)) { goto end; } diff --git a/src/lib/crypto/ecdh_ossl.cpp b/src/lib/crypto/ecdh_ossl.cpp index 831da7141..da47775fe 100644 --- a/src/lib/crypto/ecdh_ossl.cpp +++ b/src/lib/crypto/ecdh_ossl.cpp @@ -66,7 +66,6 @@ ecdh_derive_kek(uint8_t * x, } // Serialize other info, see 13.5 of RFC 4880 bis - uint8_t other_info[MAX_SP800_56A_OTHER_INFO]; const size_t hash_len = rnp::Hash::size(key.kdf_hash_alg); if (!hash_len) { // must not assert here as kdf/hash algs are not checked during key parsing @@ -75,10 +74,10 @@ ecdh_derive_kek(uint8_t * x, return RNP_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_END */ } - size_t other_len = kdf_other_info_serialize( - other_info, curve_desc, fingerprint, key.kdf_hash_alg, key.key_wrap_alg); + auto other_info = + kdf_other_info_serialize(curve_desc, fingerprint, key.kdf_hash_alg, key.key_wrap_alg); // Self-check - assert(other_len == curve_desc->OID.size() + 46); + assert(other_info.size() == curve_desc->OID.size() + 46); // Derive KEK, using the KDF from SP800-56A rnp::secure_array dgst; assert(hash_len <= PGP_MAX_HASH_SIZE); @@ -91,24 +90,17 @@ ecdh_derive_kek(uint8_t * x, /* LCOV_EXCL_END */ } size_t have = 0; - try { - for (size_t i = 1; i <= reps; i++) { - auto hash = rnp::Hash::create(key.kdf_hash_alg); - hash->add(i); - hash->add(x, xlen); - hash->add(other_info, other_len); - hash->finish(dgst.data()); - size_t bytes = std::min(hash_len, kek_len - have); - memcpy(kek + have, dgst.data(), bytes); - have += bytes; - } - return RNP_SUCCESS; - } catch (const std::exception &e) { - /* LCOV_EXCL_START */ - RNP_LOG("Failed to derive kek: %s", e.what()); - return RNP_ERROR_GENERIC; - /* LCOV_EXCL_END */ + for (size_t i = 1; i <= reps; i++) { + auto hash = rnp::Hash::create(key.kdf_hash_alg); + hash->add(i); + hash->add(x, xlen); + hash->add(other_info); + hash->finish(dgst.data()); + size_t bytes = std::min(hash_len, kek_len - have); + memcpy(kek + have, dgst.data(), bytes); + have += bytes; } + return RNP_SUCCESS; } static rnp_result_t diff --git a/src/lib/crypto/ecdh_utils.cpp b/src/lib/crypto/ecdh_utils.cpp index 8e6951244..d9e643731 100644 --- a/src/lib/crypto/ecdh_utils.cpp +++ b/src/lib/crypto/ecdh_utils.cpp @@ -49,47 +49,40 @@ static const struct ecdh_params_t { {PGP_CURVE_P256K1, PGP_HASH_SHA256, PGP_SA_AES_128}, }; -// "Anonymous Sender " in hex -static const unsigned char ANONYMOUS_SENDER[] = {0x41, 0x6E, 0x6F, 0x6E, 0x79, 0x6D, 0x6F, - 0x75, 0x73, 0x20, 0x53, 0x65, 0x6E, 0x64, - 0x65, 0x72, 0x20, 0x20, 0x20, 0x20}; - // returns size of data written to other_info -size_t -kdf_other_info_serialize(uint8_t other_info[MAX_SP800_56A_OTHER_INFO], - const ec_curve_desc_t * ec_curve, - const pgp_fingerprint_t &fingerprint, +std::vector +kdf_other_info_serialize(const ec_curve_desc_t * ec_curve, + const pgp_fingerprint_t &fp, const pgp_hash_alg_t kdf_hash, const pgp_symm_alg_t wrap_alg) { - assert(fingerprint.length >= 20); - uint8_t *buf_ptr = &other_info[0]; - + assert(fp.length >= 20); /* KDF-OtherInfo: AlgorithmID * Current implementation will always use SHA-512 and AES-256 for KEK wrapping */ - *(buf_ptr++) = static_cast(ec_curve->OID.size()); - memcpy(buf_ptr, ec_curve->OID.data(), ec_curve->OID.size() & 0xff); - buf_ptr += static_cast(ec_curve->OID.size()); - *(buf_ptr++) = PGP_PKA_ECDH; + std::vector buf; + buf.push_back(static_cast(ec_curve->OID.size())); + buf.insert(buf.end(), ec_curve->OID.begin(), ec_curve->OID.end()); + buf.push_back(PGP_PKA_ECDH); // size of following 3 params (each 1 byte) - *(buf_ptr++) = 0x03; + buf.push_back(0x03); // Value reserved for future use - *(buf_ptr++) = 0x01; + buf.push_back(0x01); // Hash used with KDF - *(buf_ptr++) = kdf_hash; + buf.push_back(kdf_hash); // Algorithm ID used for key wrapping - *(buf_ptr++) = wrap_alg; + buf.push_back(wrap_alg); /* KDF-OtherInfo: PartyUInfo * 20 bytes representing "Anonymous Sender " */ - memcpy(buf_ptr, ANONYMOUS_SENDER, sizeof(ANONYMOUS_SENDER)); - buf_ptr += sizeof(ANONYMOUS_SENDER); - + static const std::array anonymous = {0x41, 0x6E, 0x6F, 0x6E, 0x79, 0x6D, 0x6F, + 0x75, 0x73, 0x20, 0x53, 0x65, 0x6E, 0x64, + 0x65, 0x72, 0x20, 0x20, 0x20, 0x20}; + buf.insert(buf.end(), anonymous.begin(), anonymous.end()); // keep 20, as per spec - memcpy(buf_ptr, fingerprint.fingerprint, 20); - return (buf_ptr - other_info) + 20 /*anonymous_sender*/; + buf.insert(buf.end(), fp.fingerprint, fp.fingerprint + fp.length); + return buf; } bool diff --git a/src/lib/crypto/ecdh_utils.h b/src/lib/crypto/ecdh_utils.h index 2d37a713b..866055ac9 100644 --- a/src/lib/crypto/ecdh_utils.h +++ b/src/lib/crypto/ecdh_utils.h @@ -29,16 +29,14 @@ #include "ecdh.h" -#define MAX_SP800_56A_OTHER_INFO 56 // Keys up to 312 bits (+1 bytes of PKCS5 padding) #define MAX_SESSION_KEY_SIZE 40 #define MAX_AES_KEY_SIZE 32 -size_t kdf_other_info_serialize(uint8_t other_info[MAX_SP800_56A_OTHER_INFO], - const ec_curve_desc_t * ec_curve, - const pgp_fingerprint_t &fingerprint, - const pgp_hash_alg_t kdf_hash, - const pgp_symm_alg_t wrap_alg); +std::vector kdf_other_info_serialize(const ec_curve_desc_t * ec_curve, + const pgp_fingerprint_t &fp, + const pgp_hash_alg_t kdf_hash, + const pgp_symm_alg_t wrap_alg); bool pad_pkcs7(uint8_t *buf, size_t buf_len, size_t offset);