Botan 3.7.1
Crypto and TLS for C&
pk_ops.cpp
Go to the documentation of this file.
1/*
2* PK Operation Types
3* (C) 2010,2015,2023 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/internal/pk_ops_impl.h>
9
10#include <botan/hash.h>
11#include <botan/kdf.h>
12#include <botan/rng.h>
13#include <botan/internal/bit_ops.h>
14#include <botan/internal/eme.h>
15#include <botan/internal/fmt.h>
16#include <botan/internal/parsing.h>
17#include <botan/internal/scan_name.h>
18
19#if defined(BOTAN_HAS_RAW_HASH_FN)
20 #include <botan/internal/raw_hash.h>
21#endif
22
23namespace Botan {
24
26 throw Not_Implemented("This signature scheme does not have an algorithm identifier available");
27}
28
29PK_Ops::Encryption_with_EME::Encryption_with_EME(std::string_view eme) : m_eme(EME::create(eme)) {}
30
32
34 return 8 * m_eme->maximum_input_size(max_ptext_input_bits());
35}
36
37std::vector<uint8_t> PK_Ops::Encryption_with_EME::encrypt(std::span<const uint8_t> msg, RandomNumberGenerator& rng) {
38 const size_t max_input_bits = max_ptext_input_bits();
39 const size_t max_input_bytes = (max_input_bits + 7) / 8;
40 BOTAN_ARG_CHECK(msg.size() <= max_input_bytes, "Plaintext too large");
41
42 secure_vector<uint8_t> eme_output(max_input_bits);
43 const size_t written = m_eme->pad(eme_output, msg, max_input_bits, rng);
44 return raw_encrypt(std::span{eme_output}.first(written), rng);
45}
46
47PK_Ops::Decryption_with_EME::Decryption_with_EME(std::string_view eme) : m_eme(EME::create(eme)) {}
48
50
51secure_vector<uint8_t> PK_Ops::Decryption_with_EME::decrypt(uint8_t& valid_mask, std::span<const uint8_t> ctext) {
52 const secure_vector<uint8_t> raw = raw_decrypt(ctext);
53
54 secure_vector<uint8_t> ptext(raw.size());
55 auto len = m_eme->unpad(ptext, raw);
56
57 valid_mask = CT::Mask<uint8_t>::from_choice(len.has_value()).if_set_return(0xFF);
58
59 /*
60 This is potentially not const time, depending on how std::vector is
61 implemented. But since we are always reducing length, it should
62 just amount to setting the member var holding the length. Resizing
63 downwards is guaranteed to not change the capacity, and since we
64 set ctext to the maximum possible size (equal to the raw input) we
65 know that this is always, if anything, resizing smaller than the
66 capacity, so no reallocation occurs.
67 */
68
69 ptext.resize(len.value_or(0));
70 return ptext;
71}
72
74 if(kdf != "Raw") {
75 m_kdf = KDF::create_or_throw(kdf);
76 }
77}
78
80
82 std::span<const uint8_t> other_key,
83 std::span<const uint8_t> salt) {
84 if(!salt.empty() && m_kdf == nullptr) {
85 throw Invalid_Argument("PK_Key_Agreement::derive_key requires a KDF to use a salt");
86 }
87
88 secure_vector<uint8_t> z = raw_agree(other_key.data(), other_key.size());
89 if(m_kdf) {
90 return m_kdf->derive_key(key_len, z, salt.data(), salt.size());
91 }
92 return z;
93}
94
95namespace {
96
97std::unique_ptr<HashFunction> create_signature_hash(std::string_view padding) {
98 if(auto hash = HashFunction::create(padding)) {
99 return hash;
100 }
101
102 SCAN_Name req(padding);
103
104 if(req.algo_name() == "EMSA1" && req.arg_count() == 1) {
105 if(auto hash = HashFunction::create(req.arg(0))) {
106 return hash;
107 }
108 }
109
110#if defined(BOTAN_HAS_RAW_HASH_FN)
111 if(req.algo_name() == "Raw") {
112 if(req.arg_count() == 0) {
113 return std::make_unique<RawHashFunction>("Raw", 0);
114 }
115
116 if(req.arg_count() == 1) {
117 if(auto hash = HashFunction::create(req.arg(0))) {
118 return std::make_unique<RawHashFunction>(std::move(hash));
119 }
120 }
121 }
122#endif
123
124 throw Algorithm_Not_Found(padding);
125}
126
127} // namespace
128
130 Signature(), m_hash(create_signature_hash(hash)) {}
131
133
134#if defined(BOTAN_HAS_RFC6979_GENERATOR)
135std::string PK_Ops::Signature_with_Hash::rfc6979_hash_function() const {
136 std::string hash = m_hash->name();
137 if(hash != "Raw") {
138 return hash;
139 }
140 return "SHA-512";
141}
142#endif
143
145 return m_hash->name();
146}
147
148void PK_Ops::Signature_with_Hash::update(std::span<const uint8_t> msg) {
149 m_hash->update(msg);
150}
151
153 const std::vector<uint8_t> msg = m_hash->final_stdvec();
154 return raw_sign(msg, rng);
155}
156
158 Verification(), m_hash(create_signature_hash(padding)) {}
159
161
163 return m_hash->name();
164}
165
167 std::string_view pk_algo,
168 bool allow_null_parameters) {
169 const auto oid_info = split_on(alg_id.oid().to_formatted_string(), '/');
170
171 if(oid_info.size() != 2 || oid_info[0] != pk_algo) {
172 throw Decoding_Error(
173 fmt("Unexpected AlgorithmIdentifier OID {} in association with {} key", alg_id.oid(), pk_algo));
174 }
175
176 if(!alg_id.parameters_are_empty()) {
177 if(alg_id.parameters_are_null()) {
178 if(!allow_null_parameters) {
179 throw Decoding_Error(fmt("Unexpected NULL AlgorithmIdentifier parameters for {}", pk_algo));
180 }
181 } else {
182 throw Decoding_Error(fmt("Unexpected AlgorithmIdentifier parameters for {}", pk_algo));
183 }
184 }
185
186 m_hash = HashFunction::create_or_throw(oid_info[1]);
187}
188
189void PK_Ops::Verification_with_Hash::update(std::span<const uint8_t> msg) {
190 m_hash->update(msg);
191}
192
193bool PK_Ops::Verification_with_Hash::is_valid_signature(std::span<const uint8_t> sig) {
194 const std::vector<uint8_t> msg = m_hash->final_stdvec();
195 return verify(msg, sig);
196}
197
198size_t PK_Ops::KEM_Encryption_with_KDF::shared_key_length(size_t desired_shared_key_len) const {
199 if(m_kdf) {
200 return desired_shared_key_len;
201 } else {
202 return this->raw_kem_shared_key_length();
203 }
204}
205
206void PK_Ops::KEM_Encryption_with_KDF::kem_encrypt(std::span<uint8_t> out_encapsulated_key,
207 std::span<uint8_t> out_shared_key,
209 size_t desired_shared_key_len,
210 std::span<const uint8_t> salt) {
211 BOTAN_ARG_CHECK(salt.empty() || m_kdf, "PK_KEM_Encryptor::encrypt requires a KDF to use a salt");
212 BOTAN_ASSERT_NOMSG(out_encapsulated_key.size() == encapsulated_key_length());
213
214 if(m_kdf) {
216 out_shared_key.size(), desired_shared_key_len, "KDF output length and shared key length match");
217
218 secure_vector<uint8_t> raw_shared(raw_kem_shared_key_length());
219 this->raw_kem_encrypt(out_encapsulated_key, raw_shared, rng);
220 m_kdf->derive_key(out_shared_key, raw_shared, salt, {});
221 } else {
222 BOTAN_ASSERT_EQUAL(out_shared_key.size(), raw_kem_shared_key_length(), "Shared key has raw KEM output length");
223 this->raw_kem_encrypt(out_encapsulated_key, out_shared_key, rng);
224 }
225}
226
228 if(kdf != "Raw") {
229 m_kdf = KDF::create_or_throw(kdf);
230 }
231}
232
234
235size_t PK_Ops::KEM_Decryption_with_KDF::shared_key_length(size_t desired_shared_key_len) const {
236 if(m_kdf) {
237 return desired_shared_key_len;
238 } else {
239 return this->raw_kem_shared_key_length();
240 }
241}
242
243void PK_Ops::KEM_Decryption_with_KDF::kem_decrypt(std::span<uint8_t> out_shared_key,
244 std::span<const uint8_t> encapsulated_key,
245 size_t desired_shared_key_len,
246 std::span<const uint8_t> salt) {
247 BOTAN_ARG_CHECK(salt.empty() || m_kdf, "PK_KEM_Decryptor::decrypt requires a KDF to use a salt");
248
249 if(m_kdf) {
251 out_shared_key.size(), desired_shared_key_len, "KDF output length and shared key length match");
252
253 secure_vector<uint8_t> raw_shared(raw_kem_shared_key_length());
254 this->raw_kem_decrypt(raw_shared, encapsulated_key);
255 m_kdf->derive_key(out_shared_key, raw_shared, salt, {});
256 } else {
257 BOTAN_ASSERT_EQUAL(out_shared_key.size(), raw_kem_shared_key_length(), "Shared key has raw KEM output length");
258 this->raw_kem_decrypt(out_shared_key, encapsulated_key);
259 }
260}
261
263 if(kdf != "Raw") {
264 m_kdf = KDF::create_or_throw(kdf);
265 }
266}
267
269
270} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
#define BOTAN_ASSERT_EQUAL(expr1, expr2, assertion_made)
Definition assert.h:68
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:29
bool parameters_are_empty() const
Definition asn1_obj.h:484
bool parameters_are_null() const
Definition alg_id.cpp:50
const OID & oid() const
Definition asn1_obj.h:472
static constexpr Mask< T > from_choice(Choice c)
Definition ct_utils.h:413
static std::unique_ptr< HashFunction > create_or_throw(std::string_view algo_spec, std::string_view provider="")
Definition hash.cpp:298
static std::unique_ptr< HashFunction > create(std::string_view algo_spec, std::string_view provider="")
Definition hash.cpp:107
static std::unique_ptr< KDF > create_or_throw(std::string_view algo_spec, std::string_view provider="")
Definition kdf.cpp:202
std::string to_formatted_string() const
Definition asn1_oid.cpp:139
Decryption_with_EME(std::string_view eme)
Definition pk_ops.cpp:47
secure_vector< uint8_t > decrypt(uint8_t &valid_mask, std::span< const uint8_t > ctext) override
Definition pk_ops.cpp:51
std::vector< uint8_t > encrypt(std::span< const uint8_t > ptext, RandomNumberGenerator &rng) override
Definition pk_ops.cpp:37
size_t max_input_bits() const override
Definition pk_ops.cpp:33
Encryption_with_EME(std::string_view eme)
Definition pk_ops.cpp:29
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
Definition pk_ops.cpp:243
KEM_Decryption_with_KDF(std::string_view kdf)
Definition pk_ops.cpp:262
size_t shared_key_length(size_t desired_shared_key_len) const final
Definition pk_ops.cpp:235
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
Definition pk_ops.cpp:206
size_t shared_key_length(size_t desired_shared_key_len) const final
Definition pk_ops.cpp:198
KEM_Encryption_with_KDF(std::string_view kdf)
Definition pk_ops.cpp:227
Key_Agreement_with_KDF(std::string_view kdf)
Definition pk_ops.cpp:73
secure_vector< uint8_t > agree(size_t key_len, std::span< const uint8_t > other_key, std::span< const uint8_t > salt) override
Definition pk_ops.cpp:81
std::vector< uint8_t > sign(RandomNumberGenerator &rng) override
Definition pk_ops.cpp:152
std::string hash_function() const final
Definition pk_ops.cpp:144
void update(std::span< const uint8_t > input) override
Definition pk_ops.cpp:148
Signature_with_Hash(std::string_view hash)
Definition pk_ops.cpp:129
virtual AlgorithmIdentifier algorithm_identifier() const
Definition pk_ops.cpp:25
std::string hash_function() const final
Definition pk_ops.cpp:162
void update(std::span< const uint8_t > input) override
Definition pk_ops.cpp:189
Verification_with_Hash(std::string_view hash)
Definition pk_ops.cpp:157
bool is_valid_signature(std::span< const uint8_t > sig) override
Definition pk_ops.cpp:193
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
std::vector< std::string > split_on(std::string_view str, char delim)
Definition parsing.cpp:111
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61