Botan 3.11.0
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/buffer_slicer.h>
12#include <botan/internal/buffer_stuffer.h>
13
14namespace Botan {
15
16KEM_Encryption_with_Combiner::KEM_Encryption_with_Combiner(const std::vector<std::unique_ptr<Public_Key>>& public_keys,
17 std::string_view provider) :
18 m_encapsulated_key_length(0) {
19 m_encryptors.reserve(public_keys.size());
20 for(const auto& pk : public_keys) {
21 const auto& newenc = m_encryptors.emplace_back(*pk, "Raw", provider);
22 m_encapsulated_key_length += newenc.encapsulated_key_length();
23 }
24}
25
26void KEM_Encryption_with_Combiner::kem_encrypt(std::span<uint8_t> out_encapsulated_key,
27 std::span<uint8_t> out_shared_key,
29 size_t desired_shared_key_len,
30 std::span<const uint8_t> salt) {
31 BOTAN_ARG_CHECK(out_encapsulated_key.size() == encapsulated_key_length(),
32 "Encapsulated key output buffer has wrong size");
33 BOTAN_ARG_CHECK(out_shared_key.size() == shared_key_length(desired_shared_key_len),
34 "Shared key output buffer has wrong size");
35
36 std::vector<secure_vector<uint8_t>> shared_secrets;
37 shared_secrets.reserve(m_encryptors.size());
38
39 std::vector<std::vector<uint8_t>> ciphertexts;
40 ciphertexts.reserve(m_encryptors.size());
41
42 for(auto& encryptor : m_encryptors) {
43 auto [ct, ss] = KEM_Encapsulation::destructure(encryptor.encrypt(rng, 0 /* no KDF */));
44 shared_secrets.push_back(std::move(ss));
45 ciphertexts.push_back(std::move(ct));
46 }
47 combine_ciphertexts(out_encapsulated_key, ciphertexts, salt);
48 combine_shared_secrets(out_shared_key, shared_secrets, ciphertexts, desired_shared_key_len, salt);
49}
50
51void KEM_Encryption_with_Combiner::combine_ciphertexts(std::span<uint8_t> out_ciphertext,
52 const std::vector<std::vector<uint8_t>>& ciphertexts,
53 std::span<const uint8_t> salt) {
54 BOTAN_ARG_CHECK(salt.empty(), "Salt not supported by this KEM");
55 BOTAN_ARG_CHECK(ciphertexts.size() == m_encryptors.size(), "Invalid number of ciphertexts");
56 BOTAN_ARG_CHECK(out_ciphertext.size() == encapsulated_key_length(), "Invalid output buffer size");
57 BufferStuffer ct_stuffer(out_ciphertext);
58 for(size_t idx = 0; idx < ciphertexts.size(); idx++) {
59 BOTAN_ARG_CHECK(ciphertexts.at(idx).size() == m_encryptors.at(idx).encapsulated_key_length(),
60 "Invalid ciphertext length");
61 ct_stuffer.append(ciphertexts.at(idx));
62 }
63 BOTAN_ASSERT_NOMSG(ct_stuffer.full());
64}
65
67 const std::vector<std::unique_ptr<Private_Key>>& private_keys,
69 std::string_view provider) :
70 m_encapsulated_key_length(0) {
71 m_decryptors.reserve(private_keys.size());
72 for(const auto& sk : private_keys) {
73 const auto& newenc = m_decryptors.emplace_back(*sk, rng, "Raw", provider);
74 m_encapsulated_key_length += newenc.encapsulated_key_length();
75 }
76}
77
78void KEM_Decryption_with_Combiner::kem_decrypt(std::span<uint8_t> out_shared_key,
79 std::span<const uint8_t> encapsulated_key,
80 size_t desired_shared_key_len,
81 std::span<const uint8_t> salt) {
82 BOTAN_ARG_CHECK(encapsulated_key.size() == encapsulated_key_length(), "Invalid encapsulated key length");
83 BOTAN_ARG_CHECK(out_shared_key.size() == shared_key_length(desired_shared_key_len), "Invalid output buffer size");
84
85 std::vector<secure_vector<uint8_t>> shared_secrets;
86 shared_secrets.reserve(m_decryptors.size());
87 auto ciphertexts = split_ciphertexts(encapsulated_key);
88 BOTAN_ASSERT(ciphertexts.size() == m_decryptors.size(), "Correct number of ciphertexts");
89
90 for(size_t idx = 0; idx < m_decryptors.size(); idx++) {
91 shared_secrets.push_back(m_decryptors.at(idx).decrypt(ciphertexts.at(idx), 0 /* no KDF */));
92 }
93
94 combine_shared_secrets(out_shared_key, shared_secrets, ciphertexts, desired_shared_key_len, salt);
95}
96
97std::vector<std::vector<uint8_t>> KEM_Decryption_with_Combiner::split_ciphertexts(
98 std::span<const uint8_t> concat_ciphertext) {
99 BOTAN_ARG_CHECK(concat_ciphertext.size() == encapsulated_key_length(), "Wrong ciphertext length");
100 std::vector<std::vector<uint8_t>> ciphertexts;
101 ciphertexts.reserve(m_decryptors.size());
102 BufferSlicer ct_slicer(concat_ciphertext);
103 for(const auto& decryptor : m_decryptors) {
104 ciphertexts.push_back(ct_slicer.copy_as_vector(decryptor.encapsulated_key_length()));
105 }
106 BOTAN_ASSERT_NOMSG(ct_slicer.empty());
107 return ciphertexts;
108}
109
110} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:62
auto copy_as_vector(const size_t count)
Helper class to ease in-place marshalling of concatenated fixed-length values.
constexpr void append(std::span< const uint8_t > buffer)
constexpr bool full() const
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:580
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