Botan 3.8.1
Crypto and TLS for C&
hybrid_kem_ops.cpp
Go to the documentation of this file.
1/**
2* Abstraction for a combined KEM encryptors and decryptors.
3*
4* (C) 2024 Jack Lloyd
5* 2024 Fabian Albert, René Meusel - Rohde & Schwarz Cybersecurity
6*
7* Botan is released under the Simplified BSD License (see license.txt)
8*/
9#include <botan/internal/hybrid_kem_ops.h>
10
11#include <botan/internal/stl_util.h>
12
13namespace Botan {
14
15KEM_Encryption_with_Combiner::KEM_Encryption_with_Combiner(const std::vector<std::unique_ptr<Public_Key>>& public_keys,
16 std::string_view provider) :
17 m_encapsulated_key_length(0) {
18 m_encryptors.reserve(public_keys.size());
19 for(const auto& pk : public_keys) {
20 const auto& newenc = m_encryptors.emplace_back(*pk, "Raw", provider);
21 m_encapsulated_key_length += newenc.encapsulated_key_length();
22 }
23}
24
25void KEM_Encryption_with_Combiner::kem_encrypt(std::span<uint8_t> out_encapsulated_key,
26 std::span<uint8_t> out_shared_key,
28 size_t desired_shared_key_len,
29 std::span<const uint8_t> salt) {
30 BOTAN_ARG_CHECK(out_encapsulated_key.size() == encapsulated_key_length(),
31 "Encapsulated key output buffer has wrong size");
32 BOTAN_ARG_CHECK(out_shared_key.size() == shared_key_length(desired_shared_key_len),
33 "Shared key output buffer has wrong size");
34
35 std::vector<secure_vector<uint8_t>> shared_secrets;
36 shared_secrets.reserve(m_encryptors.size());
37
38 std::vector<std::vector<uint8_t>> ciphertexts;
39 ciphertexts.reserve(m_encryptors.size());
40
41 for(auto& encryptor : m_encryptors) {
42 auto [ct, ss] = KEM_Encapsulation::destructure(encryptor.encrypt(rng, 0 /* no KDF */));
43 shared_secrets.push_back(std::move(ss));
44 ciphertexts.push_back(std::move(ct));
45 }
46 combine_ciphertexts(out_encapsulated_key, ciphertexts, salt);
47 combine_shared_secrets(out_shared_key, shared_secrets, ciphertexts, desired_shared_key_len, salt);
48}
49
50void KEM_Encryption_with_Combiner::combine_ciphertexts(std::span<uint8_t> out_ciphertext,
51 const std::vector<std::vector<uint8_t>>& ciphertexts,
52 std::span<const uint8_t> salt) {
53 BOTAN_ARG_CHECK(salt.empty(), "Salt not supported by this KEM");
54 BOTAN_ARG_CHECK(ciphertexts.size() == m_encryptors.size(), "Invalid number of ciphertexts");
55 BOTAN_ARG_CHECK(out_ciphertext.size() == encapsulated_key_length(), "Invalid output buffer size");
56 BufferStuffer ct_stuffer(out_ciphertext);
57 for(size_t idx = 0; idx < ciphertexts.size(); idx++) {
58 BOTAN_ARG_CHECK(ciphertexts.at(idx).size() == m_encryptors.at(idx).encapsulated_key_length(),
59 "Invalid ciphertext length");
60 ct_stuffer.append(ciphertexts.at(idx));
61 }
62 BOTAN_ASSERT_NOMSG(ct_stuffer.full());
63}
64
66 const std::vector<std::unique_ptr<Private_Key>>& private_keys,
68 std::string_view provider) :
69 m_encapsulated_key_length(0) {
70 m_decryptors.reserve(private_keys.size());
71 for(const auto& sk : private_keys) {
72 const auto& newenc = m_decryptors.emplace_back(*sk, rng, "Raw", provider);
73 m_encapsulated_key_length += newenc.encapsulated_key_length();
74 }
75}
76
77void KEM_Decryption_with_Combiner::kem_decrypt(std::span<uint8_t> out_shared_key,
78 std::span<const uint8_t> encapsulated_key,
79 size_t desired_shared_key_len,
80 std::span<const uint8_t> salt) {
81 BOTAN_ARG_CHECK(encapsulated_key.size() == encapsulated_key_length(), "Invalid encapsulated key length");
82 BOTAN_ARG_CHECK(out_shared_key.size() == shared_key_length(desired_shared_key_len), "Invalid output buffer size");
83
84 std::vector<secure_vector<uint8_t>> shared_secrets;
85 shared_secrets.reserve(m_decryptors.size());
86 auto ciphertexts = split_ciphertexts(encapsulated_key);
87 BOTAN_ASSERT(ciphertexts.size() == m_decryptors.size(), "Correct number of ciphertexts");
88
89 for(size_t idx = 0; idx < m_decryptors.size(); idx++) {
90 shared_secrets.push_back(m_decryptors.at(idx).decrypt(ciphertexts.at(idx), 0 /* no KDF */));
91 }
92
93 combine_shared_secrets(out_shared_key, shared_secrets, ciphertexts, desired_shared_key_len, salt);
94}
95
96std::vector<std::vector<uint8_t>> KEM_Decryption_with_Combiner::split_ciphertexts(
97 std::span<const uint8_t> concat_ciphertext) {
98 BOTAN_ARG_CHECK(concat_ciphertext.size() == encapsulated_key_length(), "Wrong ciphertext length");
99 std::vector<std::vector<uint8_t>> ciphertexts;
100 ciphertexts.reserve(m_decryptors.size());
101 BufferSlicer ct_slicer(concat_ciphertext);
102 for(const auto& decryptor : m_decryptors) {
103 ciphertexts.push_back(ct_slicer.copy_as_vector(decryptor.encapsulated_key_length()));
104 }
105 BOTAN_ASSERT_NOMSG(ct_slicer.empty());
106 return ciphertexts;
107}
108
109} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:61
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:31
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:52
bool empty() const
Definition stl_util.h:130
auto copy_as_vector(const size_t count)
Definition stl_util.h:95
Helper class to ease in-place marshalling of concatenated fixed-length values.
Definition stl_util.h:143
constexpr void append(std::span< const uint8_t > buffer)
Definition stl_util.h:178
constexpr bool full() const
Definition stl_util.h:188
void kem_decrypt(std::span< uint8_t > out_shared_key, std::span< const uint8_t > encapsulated_key, size_t desired_shared_key_len, std::span< const uint8_t > salt) final
KEM_Decryption_with_Combiner(const std::vector< std::unique_ptr< Private_Key > > &private_keys, RandomNumberGenerator &rng, std::string_view provider)
size_t encapsulated_key_length() const override
The default implementation returns the sum of the encapsulated key lengths of the underlying KEMs.
virtual void combine_shared_secrets(std::span< uint8_t > out_shared_secret, const std::vector< secure_vector< uint8_t > > &shared_secrets, const std::vector< std::vector< uint8_t > > &ciphertexts, size_t desired_shared_key_len, std::span< const uint8_t > salt)=0
Describes how the shared secrets are combined to derive the final shared secret.
virtual std::vector< std::vector< uint8_t > > split_ciphertexts(std::span< const uint8_t > concat_ciphertext)
Defines how the individual ciphertexts are extracted from the combined ciphertext.
static std::pair< std::vector< uint8_t >, secure_vector< uint8_t > > destructure(KEM_Encapsulation &&kem)
Definition pubkey.h:569
KEM_Encryption_with_Combiner(const std::vector< std::unique_ptr< Public_Key > > &public_keys, std::string_view provider)
virtual void combine_ciphertexts(std::span< uint8_t > out_ciphertext, const std::vector< std::vector< uint8_t > > &ciphertexts, std::span< const uint8_t > salt)
Defines how multiple ciphertexts are combined into a single ciphertext.
void kem_encrypt(std::span< uint8_t > out_encapsulated_key, std::span< uint8_t > out_shared_key, RandomNumberGenerator &rng, size_t desired_shared_key_len, std::span< const uint8_t > salt) final
size_t encapsulated_key_length() const override
The default implementation returns the sum of the encapsulated key lengths of the underlying KEMs.
virtual void combine_shared_secrets(std::span< uint8_t > out_shared_secret, const std::vector< secure_vector< uint8_t > > &shared_secrets, const std::vector< std::vector< uint8_t > > &ciphertexts, size_t desired_shared_key_len, std::span< const uint8_t > salt)=0
Describes how the shared secrets are combined to derive the final shared secret.
virtual size_t shared_key_length(size_t desired_shared_key_len) const =0
virtual size_t shared_key_length(size_t desired_shared_key_len) const =0