Skip to content

Commit

Permalink
Use std::vector instead of fixed buffer for ECDH other_info serializa…
Browse files Browse the repository at this point in the history
…tion.
  • Loading branch information
ni4 committed Nov 13, 2024
1 parent 3ad8cd0 commit 4c5c9c2
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 96 deletions.
62 changes: 18 additions & 44 deletions src/lib/crypto/ecdh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
*/

#include <string.h>
#include <cassert>
#include <botan/ffi.h>
#include "hash_botan.hpp"
#include "ecdh.h"
Expand All @@ -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<uint8_t> &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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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];
Expand All @@ -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())) {
Expand All @@ -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;
}
Expand Down Expand Up @@ -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)) {
Expand All @@ -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;
}

Expand Down
34 changes: 13 additions & 21 deletions src/lib/crypto/ecdh_ossl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<uint8_t, PGP_MAX_HASH_SIZE> dgst;
assert(hash_len <= PGP_MAX_HASH_SIZE);
Expand All @@ -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
Expand Down
43 changes: 18 additions & 25 deletions src/lib/crypto/ecdh_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint8_t>
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<uint8_t>(ec_curve->OID.size());
memcpy(buf_ptr, ec_curve->OID.data(), ec_curve->OID.size() & 0xff);
buf_ptr += static_cast<uint8_t>(ec_curve->OID.size());
*(buf_ptr++) = PGP_PKA_ECDH;
std::vector<uint8_t> buf;
buf.push_back(static_cast<uint8_t>(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<uint8_t, 20> 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
Expand Down
10 changes: 4 additions & 6 deletions src/lib/crypto/ecdh_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint8_t> 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);

Expand Down

0 comments on commit 4c5c9c2

Please sign in to comment.