Botan 3.10.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
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 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_info = split_on(alg_id.oid().to_formatted_string(), '/');
174
175 if(oid_info.size() != 2 || oid_info[0] != pk_algo) {
176 throw Decoding_Error(
177 fmt("Unexpected AlgorithmIdentifier OID {} in association with {} key", alg_id.oid(), pk_algo));
178 }
179
180 if(!alg_id.parameters_are_empty()) {
181 if(alg_id.parameters_are_null()) {
182 if(!allow_null_parameters) {
183 throw Decoding_Error(fmt("Unexpected NULL AlgorithmIdentifier parameters for {}", pk_algo));
184 }
185 } else {
186 throw Decoding_Error(fmt("Unexpected AlgorithmIdentifier parameters for {}", pk_algo));
187 }
188 }
189
190 m_hash = HashFunction::create_or_throw(oid_info[1]);
191}
192
193void PK_Ops::Verification_with_Hash::update(std::span<const uint8_t> msg) {
194 m_hash->update(msg);
195}
196
197bool PK_Ops::Verification_with_Hash::is_valid_signature(std::span<const uint8_t> sig) {
198 const std::vector<uint8_t> msg = m_hash->final_stdvec();
199 return verify(msg, sig);
200}
201
202size_t PK_Ops::KEM_Encryption_with_KDF::shared_key_length(size_t desired_shared_key_len) const {
203 if(m_kdf) {
204 return desired_shared_key_len;
205 } else {
206 return this->raw_kem_shared_key_length();
207 }
208}
209
210void PK_Ops::KEM_Encryption_with_KDF::kem_encrypt(std::span<uint8_t> out_encapsulated_key,
211 std::span<uint8_t> out_shared_key,
213 size_t desired_shared_key_len,
214 std::span<const uint8_t> salt) {
215 BOTAN_ARG_CHECK(salt.empty() || m_kdf, "PK_KEM_Encryptor::encrypt requires a KDF to use a salt");
216 BOTAN_ASSERT_NOMSG(out_encapsulated_key.size() == encapsulated_key_length());
217
218 if(m_kdf) {
220 out_shared_key.size(), desired_shared_key_len, "KDF output length and shared key length match");
221
223 this->raw_kem_encrypt(out_encapsulated_key, raw_shared, rng);
224 m_kdf->derive_key(out_shared_key, raw_shared, salt, {});
225 } else {
226 BOTAN_ASSERT_EQUAL(out_shared_key.size(), raw_kem_shared_key_length(), "Shared key has raw KEM output length");
227 this->raw_kem_encrypt(out_encapsulated_key, out_shared_key, rng);
228 }
229}
230
232 if(kdf != "Raw") {
233 m_kdf = KDF::create_or_throw(kdf);
234 }
235}
236
238
239size_t PK_Ops::KEM_Decryption_with_KDF::shared_key_length(size_t desired_shared_key_len) const {
240 if(m_kdf) {
241 return desired_shared_key_len;
242 } else {
243 return this->raw_kem_shared_key_length();
244 }
245}
246
247void PK_Ops::KEM_Decryption_with_KDF::kem_decrypt(std::span<uint8_t> out_shared_key,
248 std::span<const uint8_t> encapsulated_key,
249 size_t desired_shared_key_len,
250 std::span<const uint8_t> salt) {
251 BOTAN_ARG_CHECK(salt.empty() || m_kdf, "PK_KEM_Decryptor::decrypt requires a KDF to use a salt");
252
253 if(m_kdf) {
255 out_shared_key.size(), desired_shared_key_len, "KDF output length and shared key length match");
256
258 this->raw_kem_decrypt(raw_shared, encapsulated_key);
259 m_kdf->derive_key(out_shared_key, raw_shared, salt, {});
260 } else {
261 BOTAN_ASSERT_EQUAL(out_shared_key.size(), raw_kem_shared_key_length(), "Shared key has raw KEM output length");
262 this->raw_kem_decrypt(out_shared_key, encapsulated_key);
263 }
264}
265
267 if(kdf != "Raw") {
268 m_kdf = KDF::create_or_throw(kdf);
269 }
270}
271
273
274} // 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:491
bool parameters_are_null() const
Definition alg_id.cpp:49
const OID & oid() const
Definition asn1_obj.h:479
static constexpr Mask< T > from_choice(Choice c)
Definition ct_utils.h:430
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:204
std::string to_formatted_string() const
Definition asn1_oid.cpp:139
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:247
KEM_Decryption_with_KDF(std::string_view kdf)
Definition pk_ops.cpp:266
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:239
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:210
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:202
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:231
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:193
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:197
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:69