11#include <botan/internal/hybrid_public_key.h>
13#include <botan/ec_group.h>
14#include <botan/pk_algs.h>
16#include <botan/internal/fmt.h>
17#include <botan/internal/hybrid_kem_ops.h>
18#include <botan/internal/kex_to_kem_adapter.h>
19#include <botan/internal/pk_ops_impl.h>
20#include <botan/internal/stl_util.h>
26std::vector<std::pair<std::string, std::string>> algorithm_specs_for_group(
Group_Params group) {
29 switch(group.code()) {
41 case Group_Params::HYBRID_X25519_ML_KEM_768:
42 return {{
"ML-KEM",
"ML-KEM-768"}, {
"X25519",
"X25519"}};
43 case Group_Params::HYBRID_SECP256R1_ML_KEM_768:
44 return {{
"ECDH",
"secp256r1"}, {
"ML-KEM",
"ML-KEM-768"}};
45 case Group_Params::HYBRID_SECP384R1_ML_KEM_1024:
46 return {{
"ECDH",
"secp384r1"}, {
"ML-KEM",
"ML-KEM-1024"}};
48 case Group_Params::HYBRID_X25519_eFRODOKEM_640_SHAKE_OQS:
49 return {{
"X25519",
"X25519"}, {
"FrodoKEM",
"eFrodoKEM-640-SHAKE"}};
50 case Group_Params::HYBRID_X25519_eFRODOKEM_640_AES_OQS:
51 return {{
"X25519",
"X25519"}, {
"FrodoKEM",
"eFrodoKEM-640-AES"}};
52 case Group_Params::HYBRID_X448_eFRODOKEM_976_SHAKE_OQS:
53 return {{
"X448",
"X448"}, {
"FrodoKEM",
"eFrodoKEM-976-SHAKE"}};
54 case Group_Params::HYBRID_X448_eFRODOKEM_976_AES_OQS:
55 return {{
"X448",
"X448"}, {
"FrodoKEM",
"eFrodoKEM-976-AES"}};
57 case Group_Params::HYBRID_SECP256R1_eFRODOKEM_640_SHAKE_OQS:
58 return {{
"ECDH",
"secp256r1"}, {
"FrodoKEM",
"eFrodoKEM-640-SHAKE"}};
59 case Group_Params::HYBRID_SECP256R1_eFRODOKEM_640_AES_OQS:
60 return {{
"ECDH",
"secp256r1"}, {
"FrodoKEM",
"eFrodoKEM-640-AES"}};
62 case Group_Params::HYBRID_SECP384R1_eFRODOKEM_976_SHAKE_OQS:
63 return {{
"ECDH",
"secp384r1"}, {
"FrodoKEM",
"eFrodoKEM-976-SHAKE"}};
64 case Group_Params::HYBRID_SECP384R1_eFRODOKEM_976_AES_OQS:
65 return {{
"ECDH",
"secp384r1"}, {
"FrodoKEM",
"eFrodoKEM-976-AES"}};
67 case Group_Params::HYBRID_SECP521R1_eFRODOKEM_1344_SHAKE_OQS:
68 return {{
"ECDH",
"secp521r1"}, {
"FrodoKEM",
"eFrodoKEM-1344-SHAKE"}};
69 case Group_Params::HYBRID_SECP521R1_eFRODOKEM_1344_AES_OQS:
70 return {{
"ECDH",
"secp521r1"}, {
"FrodoKEM",
"eFrodoKEM-1344-AES"}};
77std::vector<AlgorithmIdentifier> algorithm_identifiers_for_group(
Group_Params group) {
80 const auto specs = algorithm_specs_for_group(group);
81 std::vector<AlgorithmIdentifier> result;
82 result.reserve(specs.size());
91 for(
const auto& spec : specs) {
92 if(spec.first ==
"ECDH") {
102std::vector<size_t> public_key_lengths_for_group(
Group_Params group) {
109 switch(group.code()) {
110 case Group_Params::HYBRID_X25519_ML_KEM_768:
112 case Group_Params::HYBRID_SECP256R1_ML_KEM_768:
114 case Group_Params::HYBRID_SECP384R1_ML_KEM_1024:
117 case Group_Params::HYBRID_X25519_eFRODOKEM_640_SHAKE_OQS:
118 case Group_Params::HYBRID_X25519_eFRODOKEM_640_AES_OQS:
121 case Group_Params::HYBRID_X448_eFRODOKEM_976_SHAKE_OQS:
122 case Group_Params::HYBRID_X448_eFRODOKEM_976_AES_OQS:
125 case Group_Params::HYBRID_SECP256R1_eFRODOKEM_640_SHAKE_OQS:
126 case Group_Params::HYBRID_SECP256R1_eFRODOKEM_640_AES_OQS:
129 case Group_Params::HYBRID_SECP384R1_eFRODOKEM_976_SHAKE_OQS:
130 case Group_Params::HYBRID_SECP384R1_eFRODOKEM_976_AES_OQS:
133 case Group_Params::HYBRID_SECP521R1_eFRODOKEM_1344_SHAKE_OQS:
134 case Group_Params::HYBRID_SECP521R1_eFRODOKEM_1344_AES_OQS:
142std::vector<std::unique_ptr<Public_Key>> convert_kex_to_kem_pks(std::vector<std::unique_ptr<Public_Key>> pks) {
143 std::vector<std::unique_ptr<Public_Key>> result;
144 std::transform(pks.begin(), pks.end(), std::back_inserter(result), [](
auto& key) -> std::unique_ptr<Public_Key> {
145 BOTAN_ARG_CHECK(key != nullptr,
"Public key list contains a nullptr");
146 if(key->supports_operation(PublicKeyOperation::KeyAgreement) &&
147 !key->supports_operation(PublicKeyOperation::KeyEncapsulation)) {
148 return std::make_unique<KEX_to_KEM_Adapter_PublicKey>(std::move(key));
150 return std::move(key);
156std::vector<std::unique_ptr<Private_Key>> convert_kex_to_kem_sks(std::vector<std::unique_ptr<Private_Key>> sks) {
157 std::vector<std::unique_ptr<Private_Key>> result;
158 std::transform(sks.begin(), sks.end(), std::back_inserter(result), [](
auto& key) -> std::unique_ptr<Private_Key> {
159 BOTAN_ARG_CHECK(key != nullptr,
"Private key list contains a nullptr");
160 if(key->supports_operation(PublicKeyOperation::KeyAgreement) &&
161 !key->supports_operation(PublicKeyOperation::KeyEncapsulation)) {
162 auto* ka_key = dynamic_cast<PK_Key_Agreement_Key*>(key.get());
163 BOTAN_ASSERT_NONNULL(ka_key);
165 return std::make_unique<KEX_to_KEM_Adapter_PrivateKey>(std::unique_ptr<PK_Key_Agreement_Key>(ka_key));
167 return std::move(key);
173template <
typename KEM_Operation>
174void concat_secret_combiner(KEM_Operation& op,
175 std::span<uint8_t> out_shared_secret,
176 const std::vector<secure_vector<uint8_t>>& shared_secrets,
177 size_t desired_shared_key_len) {
178 BOTAN_ARG_CHECK(out_shared_secret.size() == op.shared_key_length(desired_shared_key_len),
179 "Invalid output buffer size");
181 BufferStuffer shared_secret_stuffer(out_shared_secret);
182 for(
const auto& ss : shared_secrets) {
183 shared_secret_stuffer.append(ss);
188template <
typename KEM_Operation>
189size_t concat_shared_key_length(
const std::vector<KEM_Operation>& operation) {
191 operation,
size_t(0), [](
size_t acc,
const auto& op) {
return acc + op.shared_key_length(0 ); });
195class Hybrid_TLS_KEM_Encryptor final :
public KEM_Encryption_with_Combiner {
197 Hybrid_TLS_KEM_Encryptor(
const std::vector<std::unique_ptr<Public_Key>>& public_keys, std::string_view provider) :
198 KEM_Encryption_with_Combiner(public_keys, provider) {}
200 void combine_shared_secrets(std::span<uint8_t> out_shared_secret,
201 const std::vector<secure_vector<uint8_t>>& shared_secrets,
202 const std::vector<std::vector<uint8_t>>& ,
203 size_t desired_shared_key_len,
204 std::span<const uint8_t> )
override {
205 concat_secret_combiner(*
this, out_shared_secret, shared_secrets, desired_shared_key_len);
208 size_t shared_key_length(
size_t )
const override {
209 return concat_shared_key_length(encryptors());
214class Hybrid_TLS_KEM_Decryptor final :
public KEM_Decryption_with_Combiner {
216 Hybrid_TLS_KEM_Decryptor(
const std::vector<std::unique_ptr<Private_Key>>& private_keys,
217 RandomNumberGenerator& rng,
218 const std::string_view provider) :
219 KEM_Decryption_with_Combiner(private_keys, rng, provider) {}
221 void combine_shared_secrets(std::span<uint8_t> out_shared_secret,
222 const std::vector<secure_vector<uint8_t>>& shared_secrets,
223 const std::vector<std::vector<uint8_t>>& ,
224 size_t desired_shared_key_len,
225 std::span<const uint8_t> )
override {
226 concat_secret_combiner(*
this, out_shared_secret, shared_secrets, desired_shared_key_len);
229 size_t shared_key_length(
size_t )
const override {
230 return concat_shared_key_length(decryptors());
237 Group_Params group, std::span<const uint8_t> concatenated_public_keys) {
238 const auto public_key_lengths = public_key_lengths_for_group(group);
239 auto alg_ids = algorithm_identifiers_for_group(group);
242 const auto expected_public_keys_length =
243 reduce(public_key_lengths,
size_t(0), [](
size_t acc,
size_t len) {
return acc + len; });
244 if(expected_public_keys_length != concatenated_public_keys.size()) {
245 throw Decoding_Error(
"Concatenated public values have an unexpected length");
248 BufferSlicer public_key_slicer(concatenated_public_keys);
249 std::vector<std::unique_ptr<Public_Key>> pks;
250 pks.reserve(alg_ids.size());
251 for(
size_t idx = 0; idx < alg_ids.size(); ++idx) {
252 pks.emplace_back(
load_public_key(alg_ids[idx], public_key_slicer.
take(public_key_lengths[idx])));
255 return std::make_unique<Hybrid_KEM_PublicKey>(std::move(pks));
293 return reduce(
public_keys(), std::vector<uint8_t>(), [](
auto pkb,
const auto& key) {
294 return concat(pkb, key->raw_public_key_bits());
303 std::string_view params, std::string_view provider)
const {
304 if(params !=
"Raw" && !params.empty()) {
307 return std::make_unique<Hybrid_TLS_KEM_Encryptor>(
public_keys(), provider);
312 const auto algo_spec = algorithm_specs_for_group(group);
315 for(
const auto& spec : algo_spec) {
318 return std::make_unique<Hybrid_KEM_PrivateKey>(std::move(
private_keys));
323 if(params !=
"Raw" && !params.empty()) {
326 return std::make_unique<Hybrid_TLS_KEM_Decryptor>(
private_keys(), rng, provider);
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_ARG_CHECK(expr, msg)
std::span< const uint8_t > take(const size_t count)
static EC_Group from_name(std::string_view name)
std::vector< uint8_t > DER_encode(EC_Group_Encoding form) const
const std::vector< std::unique_ptr< Private_Key > > & private_keys() const
Hybrid_PrivateKey(const Hybrid_PrivateKey &)=delete
static std::vector< std::unique_ptr< Public_Key > > extract_public_keys(const std::vector< std::unique_ptr< Private_Key > > &private_keys)
Hybrid_PublicKey(std::vector< std::unique_ptr< Public_Key > > public_keys)
Constructor for a list of multiple KEM public keys.
std::vector< std::unique_ptr< Private_Key > > generate_other_sks_from_pks(RandomNumberGenerator &rng) const
Helper function for generate_another. Generate a new private key for each public key in this hybrid k...
const std::vector< std::unique_ptr< Public_Key > > & public_keys() const
static std::unique_ptr< Hybrid_KEM_PrivateKey > generate_from_group(Group_Params group, RandomNumberGenerator &rng)
std::unique_ptr< PK_Ops::KEM_Decryption > create_kem_decryption_op(RandomNumberGenerator &rng, std::string_view params, std::string_view provider="base") const override
Hybrid_KEM_PrivateKey(std::vector< std::unique_ptr< Private_Key > > private_keys)
AlgorithmIdentifier algorithm_identifier() const override
std::vector< uint8_t > raw_public_key_bits() const override
Hybrid_KEM_PublicKey(std::vector< std::unique_ptr< Public_Key > > pks)
static std::unique_ptr< Hybrid_KEM_PublicKey > load_for_group(Group_Params group, std::span< const uint8_t > concatenated_public_values)
std::unique_ptr< Private_Key > generate_another(RandomNumberGenerator &rng) const final
std::string algo_name() const override
std::unique_ptr< PK_Ops::KEM_Encryption > create_kem_encryption_op(std::string_view params, std::string_view provider="base") const override
std::vector< uint8_t > public_key_bits() const override
std::unique_ptr< Private_Key > create_private_key(std::string_view alg_name, RandomNumberGenerator &rng, std::string_view params, std::string_view provider)
RetT reduce(const std::vector< KeyT > &keys, RetT acc, ReducerT reducer)
constexpr auto concat(Rs &&... ranges)
std::unique_ptr< Public_Key > load_public_key(const AlgorithmIdentifier &alg_id, std::span< const uint8_t > key_bits)