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