Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
FAlbertDev committed Jul 4, 2023
1 parent 01eb20c commit ddef1fd
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 49 deletions.
35 changes: 13 additions & 22 deletions src/lib/tls/tls13_pqc/hybrid_public_key.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,26 +209,19 @@ class Hybrid_KEM_Encryption_Operation final : public PK_Ops::KEM_Encryption_with
});
}

void raw_kem_encrypt(secure_vector<uint8_t>& out_encapsulated_key,
secure_vector<uint8_t>& raw_shared_key,
void raw_kem_encrypt(std::span<uint8_t> out_encapsulated_key,
std::span<uint8_t> raw_shared_key,
Botan::RandomNumberGenerator& rng) override {
out_encapsulated_key.resize(encapsulated_key_length());
raw_shared_key.resize(raw_kem_shared_key_length());
BOTAN_ASSERT_NOMSG(out_encapsulated_key.size() == encapsulated_key_length());
BOTAN_ASSERT_NOMSG(raw_shared_key.size() == raw_kem_shared_key_length());

BufferStuffer encaps_key_stuffer(out_encapsulated_key);
BufferStuffer shared_key_stuffer(raw_shared_key);

for(auto& kem_enc : m_kem_encryptors) {
// TODO: Once PK_KEM_Encryptor uses std::span for its out-params, we
// probably want to pre-allocate the upstream out-params and
// use the BufferStuffer helper to place the downstream KEM
// outputs in the right location. Avoiding lots of copy and alloc.
// See also Hybrid_KEM_Decryption_Operation
secure_vector<uint8_t> out_encaps_buffer;
secure_vector<uint8_t> out_shared_key_buffer;
kem_enc->encrypt(out_encaps_buffer, out_shared_key_buffer, 0 /* no KDF */, rng);
encaps_key_stuffer.append(out_encaps_buffer);
shared_key_stuffer.append(out_shared_key_buffer);
kem_enc->encrypt(encaps_key_stuffer.next(kem_enc->encapsulated_key_length()),
shared_key_stuffer.next(kem_enc->shared_key_length(0 /* no KDF */)),
rng);
}
}

Expand Down Expand Up @@ -328,18 +321,16 @@ class Hybrid_KEM_Decryption final : public PK_Ops::KEM_Decryption_with_KDF {
});
}

secure_vector<uint8_t> raw_kem_decrypt(const uint8_t encap_key[], size_t len) override {
secure_vector<uint8_t> shared_secret(raw_kem_shared_key_length());
void raw_kem_decrypt(std::span<uint8_t> out_shared_key, std::span<const uint8_t> encap_key) override {
BOTAN_ASSERT_NOMSG(out_shared_key.size() == raw_kem_shared_key_length());

BufferSlicer encap_key_slicer({encap_key, len});
BufferStuffer shared_secret_stuffer(shared_secret);
BufferSlicer encap_key_slicer(encap_key);
BufferStuffer shared_secret_stuffer(out_shared_key);

for(auto& [decryptor, encapsulation_length] : m_decryptors_with_encapsulation_lengths) {
const auto public_value_part = encap_key_slicer.take(encapsulation_length);
shared_secret_stuffer.append(decryptor->decrypt(public_value_part, 0 /* no KDF */, {}));
decryptor->decrypt(shared_secret_stuffer.next(decryptor->shared_key_length(0 /* no KDF */)),
encap_key_slicer.take(encapsulation_length));
}

return shared_secret;
}

size_t raw_kem_shared_key_length() const override {
Expand Down
31 changes: 23 additions & 8 deletions src/lib/tls/tls13_pqc/kex_to_kem_adapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,14 +141,26 @@ class KEX_to_KEM_Adapter_Encryption_Operation final : public PK_Ops::KEM_Encrypt

size_t encapsulated_key_length() const override { return kex_public_value(m_public_key).size(); }

void raw_kem_encrypt(secure_vector<uint8_t>& out_encapsulated_key,
secure_vector<uint8_t>& raw_shared_key,
void raw_kem_encrypt(std::span<uint8_t> out_encapsulated_key,
std::span<uint8_t> raw_shared_key,
Botan::RandomNumberGenerator& rng) override {
const auto sk = generate_key_agreement_private_key(m_public_key, rng);
raw_shared_key = PK_Key_Agreement(*sk, rng, "Raw", m_provider)
.derive_key(0 /* no KDF */, kex_public_value(m_public_key))
.bits_of();
out_encapsulated_key = lock(sk->public_value());
const auto shared_key = PK_Key_Agreement(*sk, rng, "Raw", m_provider)
.derive_key(0 /* no KDF */, kex_public_value(m_public_key))
.bits_of();

const auto public_value = sk->public_value();

// TODO: perhaps avoid these copies by providing std::span out-params
// for `PK_Key_Agreement::derive_key()` and
// `PK_Key_Agreement_Key::public_value()`
BOTAN_ASSERT_EQUAL(public_value.size(),
out_encapsulated_key.size(),
"KEX-to-KEM Adapter: encapsulated key out-param has correct length");
BOTAN_ASSERT_EQUAL(
shared_key.size(), raw_shared_key.size(), "KEX-to-KEM Adapter: shared key out-param has correct length");
std::copy(public_value.begin(), public_value.end(), out_encapsulated_key.begin());
std::copy(shared_key.begin(), shared_key.end(), raw_shared_key.begin());
}

private:
Expand All @@ -164,8 +176,11 @@ class KEX_to_KEM_Decryption_Operation final : public PK_Ops::KEM_Decryption_with
const std::string_view provider) :
PK_Ops::KEM_Decryption_with_KDF(kdf), m_operation(key, rng, "Raw", provider) {}

secure_vector<uint8_t> raw_kem_decrypt(const uint8_t encap_key[], size_t len) override {
return m_operation.derive_key(0 /* no KDF */, {encap_key, len}).bits_of();
void raw_kem_decrypt(std::span<uint8_t> out_shared_key, std::span<const uint8_t> encap_key) override {
secure_vector<uint8_t> shared_secret = m_operation.derive_key(0 /* no KDF */, encap_key).bits_of();
BOTAN_ASSERT_EQUAL(
shared_secret.size(), out_shared_key.size(), "KEX-to-KEM Adapter: shared key out-param has correct length");
std::copy(shared_secret.begin(), shared_secret.end(), out_shared_key.begin());
}

size_t raw_kem_shared_key_length() const override { return m_operation.agreed_value_size(); }
Expand Down
5 changes: 0 additions & 5 deletions src/lib/tls/tls_callbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,11 +255,6 @@ class BOTAN_PUBLIC_API(2, 0) Callbacks {
const std::vector<uint8_t>& msg,
const std::vector<uint8_t>& sig);

struct Encapsulation_Result {
std::vector<uint8_t> encapsulated_bytes;
secure_vector<uint8_t> shared_secret;
};

/**
* Generate an ephemeral KEM key for a TLS 1.3 handshake
*
Expand Down
27 changes: 13 additions & 14 deletions src/tests/test_tls_hybrid_kem_key.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,24 +117,23 @@ void roundtrip_test(Test::Result& result, Ts... kex_kem_fn) {
auto& rng = Test::rng();

Botan::PK_KEM_Encryptor encryptor(hybrid_public_key, "Raw");
Botan::secure_vector<uint8_t> shared_secret;
Botan::secure_vector<uint8_t> encapsulated_key;
encryptor.encrypt(encapsulated_key, shared_secret, 0, rng);
const auto kem_result = encryptor.encrypt(rng);

const auto expected_shared_secret_length = length_of_hybrid_shared_key(kex_kem_fn...);
const auto expected_ciphertext_length = length_of_hybrid_ciphertext(kex_kem_fn...);
const auto expected_public_key_length = length_of_hybrid_public_value(kex_kem_fn...);

result.test_eq("ciphertext has expected length", encapsulated_key.size(), expected_ciphertext_length);
result.test_eq("shared secret has expected length", shared_secret.size(), expected_shared_secret_length);
result.test_eq(
"ciphertext has expected length", kem_result.encapsulated_shared_key().size(), expected_ciphertext_length);
result.test_eq("shared secret has expected length", kem_result.shared_key().size(), expected_shared_secret_length);
result.test_eq(
"expected length of ciphertext is as expected", encryptor.encapsulated_key_length(), expected_ciphertext_length);
result.test_eq("shared secret has expected length", encryptor.shared_key_length(0), expected_shared_secret_length);

Botan::PK_KEM_Decryptor decryptor(hybrid_key, rng, "Raw");
Botan::secure_vector<uint8_t> decaps_shared_secret = decryptor.decrypt(encapsulated_key, 0, {});
Botan::secure_vector<uint8_t> decaps_shared_secret = decryptor.decrypt(kem_result.encapsulated_shared_key(), 0, {});

result.test_eq("shared secret after KEM roundtrip matches", decaps_shared_secret, shared_secret);
result.test_eq("shared secret after KEM roundtrip matches", decaps_shared_secret, kem_result.shared_key());
result.test_eq(
"expected shared secret has expected length", decryptor.shared_key_length(0), expected_shared_secret_length);
result.test_eq("shared secret has expected length", decaps_shared_secret.size(), expected_shared_secret_length);
Expand Down Expand Up @@ -204,20 +203,20 @@ void kex_to_kem_roundtrip(Test::Result& result,
auto& rng = Test::rng();

Botan::PK_KEM_Encryptor encryptor(kexkem_public_key, "Raw");
Botan::secure_vector<uint8_t> shared_secret;
Botan::secure_vector<uint8_t> encapsulated_key;
encryptor.encrypt(encapsulated_key, shared_secret, 0, rng);
const auto kem_result = encryptor.encrypt(rng);

result.test_eq("ciphertext has expected length", encapsulated_key.size(), encryptor.encapsulated_key_length());
result.test_eq("shared secret has expected length", shared_secret.size(), encryptor.shared_key_length(0));
result.test_eq("ciphertext has expected length",
kem_result.encapsulated_shared_key().size(),
encryptor.encapsulated_key_length());
result.test_eq("shared secret has expected length", kem_result.shared_key().size(), encryptor.shared_key_length(0));

Botan::PK_KEM_Decryptor decryptor(kexkem_key, rng, "Raw");
Botan::secure_vector<uint8_t> decaps_shared_secret = decryptor.decrypt(encapsulated_key, 0, {});
Botan::secure_vector<uint8_t> decaps_shared_secret = decryptor.decrypt(kem_result.encapsulated_shared_key(), 0, {});

result.test_eq(
"decapsulated shared secret has expected length", decaps_shared_secret.size(), decryptor.shared_key_length(0));

result.test_eq("shared secret after KEM roundtrip matches", decaps_shared_secret, shared_secret);
result.test_eq("shared secret after KEM roundtrip matches", decaps_shared_secret, kem_result.shared_key());
}

std::vector<Test::Result> kex_to_kem_adapter() {
Expand Down

0 comments on commit ddef1fd

Please sign in to comment.