Coverage Report

Created: 2025-04-11 06:34

/src/botan/src/lib/pubkey/pk_ops.cpp
Line
Count
Source (jump to first uncovered line)
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
23
namespace Botan {
24
25
0
AlgorithmIdentifier PK_Ops::Signature::algorithm_identifier() const {
26
0
   throw Not_Implemented("This signature scheme does not have an algorithm identifier available");
27
0
}
28
29
0
PK_Ops::Encryption_with_EME::Encryption_with_EME(std::string_view eme) : m_eme(EME::create(eme)) {}
30
31
0
PK_Ops::Encryption_with_EME::~Encryption_with_EME() = default;
32
33
0
size_t PK_Ops::Encryption_with_EME::max_input_bits() const {
34
0
   return 8 * m_eme->maximum_input_size(max_ptext_input_bits());
35
0
}
36
37
0
std::vector<uint8_t> PK_Ops::Encryption_with_EME::encrypt(std::span<const uint8_t> msg, RandomNumberGenerator& rng) {
38
0
   const size_t max_input_bits = max_ptext_input_bits();
39
0
   const size_t max_input_bytes = (max_input_bits + 7) / 8;
40
0
   BOTAN_ARG_CHECK(msg.size() <= max_input_bytes, "Plaintext too large");
41
42
0
   secure_vector<uint8_t> eme_output(max_input_bits);
43
0
   const size_t written = m_eme->pad(eme_output, msg, max_input_bits, rng);
44
0
   return raw_encrypt(std::span{eme_output}.first(written), rng);
45
0
}
46
47
0
PK_Ops::Decryption_with_EME::Decryption_with_EME(std::string_view eme) : m_eme(EME::create(eme)) {}
48
49
0
PK_Ops::Decryption_with_EME::~Decryption_with_EME() = default;
50
51
0
secure_vector<uint8_t> PK_Ops::Decryption_with_EME::decrypt(uint8_t& valid_mask, std::span<const uint8_t> ctext) {
52
0
   const secure_vector<uint8_t> raw = raw_decrypt(ctext);
53
54
0
   secure_vector<uint8_t> ptext(raw.size());
55
0
   auto len = m_eme->unpad(ptext, raw);
56
57
0
   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
0
   ptext.resize(len.value_or(0));
70
0
   return ptext;
71
0
}
72
73
2.31k
PK_Ops::Key_Agreement_with_KDF::Key_Agreement_with_KDF(std::string_view kdf) {
74
2.31k
   if(kdf != "Raw") {
75
0
      m_kdf = KDF::create_or_throw(kdf);
76
0
   }
77
2.31k
}
78
79
2.31k
PK_Ops::Key_Agreement_with_KDF::~Key_Agreement_with_KDF() = default;
80
81
secure_vector<uint8_t> PK_Ops::Key_Agreement_with_KDF::agree(size_t key_len,
82
                                                             std::span<const uint8_t> other_key,
83
2.31k
                                                             std::span<const uint8_t> salt) {
84
2.31k
   if(!salt.empty() && m_kdf == nullptr) {
85
0
      throw Invalid_Argument("PK_Key_Agreement::derive_key requires a KDF to use a salt");
86
0
   }
87
88
2.31k
   secure_vector<uint8_t> z = raw_agree(other_key.data(), other_key.size());
89
2.31k
   if(m_kdf) {
90
0
      return m_kdf->derive_key(key_len, z, salt.data(), salt.size());
91
0
   }
92
2.31k
   return z;
93
2.31k
}
94
95
namespace {
96
97
190
std::unique_ptr<HashFunction> create_signature_hash(std::string_view padding) {
98
190
   if(auto hash = HashFunction::create(padding)) {
99
190
      return hash;
100
190
   }
101
102
0
   SCAN_Name req(padding);
103
104
0
   if(req.algo_name() == "EMSA1" && req.arg_count() == 1) {
105
0
      if(auto hash = HashFunction::create(req.arg(0))) {
106
0
         return hash;
107
0
      }
108
0
   }
109
110
0
#if defined(BOTAN_HAS_RAW_HASH_FN)
111
0
   if(req.algo_name() == "Raw") {
112
0
      if(req.arg_count() == 0) {
113
0
         return std::make_unique<RawHashFunction>("Raw", 0);
114
0
      }
115
116
0
      if(req.arg_count() == 1) {
117
0
         if(auto hash = HashFunction::create(req.arg(0))) {
118
0
            return std::make_unique<RawHashFunction>(std::move(hash));
119
0
         }
120
0
      }
121
0
   }
122
0
#endif
123
124
0
   throw Algorithm_Not_Found(padding);
125
0
}
126
127
}  // namespace
128
129
PK_Ops::Signature_with_Hash::Signature_with_Hash(std::string_view hash) :
130
0
      Signature(), m_hash(create_signature_hash(hash)) {}
131
132
0
PK_Ops::Signature_with_Hash::~Signature_with_Hash() = default;
133
134
#if defined(BOTAN_HAS_RFC6979_GENERATOR)
135
0
std::string PK_Ops::Signature_with_Hash::rfc6979_hash_function() const {
136
0
   std::string hash = m_hash->name();
137
0
   if(hash != "Raw") {
138
0
      return hash;
139
0
   }
140
0
   return "SHA-512";
141
0
}
142
#endif
143
144
0
std::string PK_Ops::Signature_with_Hash::hash_function() const {
145
0
   return m_hash->name();
146
0
}
147
148
0
void PK_Ops::Signature_with_Hash::update(std::span<const uint8_t> msg) {
149
0
   m_hash->update(msg);
150
0
}
151
152
0
std::vector<uint8_t> PK_Ops::Signature_with_Hash::sign(RandomNumberGenerator& rng) {
153
0
   const std::vector<uint8_t> msg = m_hash->final_stdvec();
154
0
   return raw_sign(msg, rng);
155
0
}
156
157
PK_Ops::Verification_with_Hash::Verification_with_Hash(std::string_view padding) :
158
190
      Verification(), m_hash(create_signature_hash(padding)) {}
159
160
821
PK_Ops::Verification_with_Hash::~Verification_with_Hash() = default;
161
162
36
std::string PK_Ops::Verification_with_Hash::hash_function() const {
163
36
   return m_hash->name();
164
36
}
165
166
PK_Ops::Verification_with_Hash::Verification_with_Hash(const AlgorithmIdentifier& alg_id,
167
                                                       std::string_view pk_algo,
168
685
                                                       bool allow_null_parameters) {
169
685
   const auto oid_info = split_on(alg_id.oid().to_formatted_string(), '/');
170
171
685
   if(oid_info.size() != 2 || oid_info[0] != pk_algo) {
172
17
      throw Decoding_Error(
173
17
         fmt("Unexpected AlgorithmIdentifier OID {} in association with {} key", alg_id.oid(), pk_algo));
174
17
   }
175
176
668
   if(!alg_id.parameters_are_empty()) {
177
37
      if(alg_id.parameters_are_null()) {
178
30
         if(!allow_null_parameters) {
179
30
            throw Decoding_Error(fmt("Unexpected NULL AlgorithmIdentifier parameters for {}", pk_algo));
180
30
         }
181
30
      } else {
182
7
         throw Decoding_Error(fmt("Unexpected AlgorithmIdentifier parameters for {}", pk_algo));
183
7
      }
184
37
   }
185
186
631
   m_hash = HashFunction::create_or_throw(oid_info[1]);
187
631
}
188
189
821
void PK_Ops::Verification_with_Hash::update(std::span<const uint8_t> msg) {
190
821
   m_hash->update(msg);
191
821
}
192
193
802
bool PK_Ops::Verification_with_Hash::is_valid_signature(std::span<const uint8_t> sig) {
194
802
   const std::vector<uint8_t> msg = m_hash->final_stdvec();
195
802
   return verify(msg, sig);
196
802
}
197
198
0
size_t PK_Ops::KEM_Encryption_with_KDF::shared_key_length(size_t desired_shared_key_len) const {
199
0
   if(m_kdf) {
200
0
      return desired_shared_key_len;
201
0
   } else {
202
0
      return this->raw_kem_shared_key_length();
203
0
   }
204
0
}
205
206
void PK_Ops::KEM_Encryption_with_KDF::kem_encrypt(std::span<uint8_t> out_encapsulated_key,
207
                                                  std::span<uint8_t> out_shared_key,
208
                                                  RandomNumberGenerator& rng,
209
                                                  size_t desired_shared_key_len,
210
0
                                                  std::span<const uint8_t> salt) {
211
0
   BOTAN_ARG_CHECK(salt.empty() || m_kdf, "PK_KEM_Encryptor::encrypt requires a KDF to use a salt");
212
0
   BOTAN_ASSERT_NOMSG(out_encapsulated_key.size() == encapsulated_key_length());
213
214
0
   if(m_kdf) {
215
0
      BOTAN_ASSERT_EQUAL(
216
0
         out_shared_key.size(), desired_shared_key_len, "KDF output length and shared key length match");
217
218
0
      secure_vector<uint8_t> raw_shared(raw_kem_shared_key_length());
219
0
      this->raw_kem_encrypt(out_encapsulated_key, raw_shared, rng);
220
0
      m_kdf->derive_key(out_shared_key, raw_shared, salt, {});
221
0
   } else {
222
0
      BOTAN_ASSERT_EQUAL(out_shared_key.size(), raw_kem_shared_key_length(), "Shared key has raw KEM output length");
223
0
      this->raw_kem_encrypt(out_encapsulated_key, out_shared_key, rng);
224
0
   }
225
0
}
226
227
0
PK_Ops::KEM_Encryption_with_KDF::KEM_Encryption_with_KDF(std::string_view kdf) {
228
0
   if(kdf != "Raw") {
229
0
      m_kdf = KDF::create_or_throw(kdf);
230
0
   }
231
0
}
232
233
0
PK_Ops::KEM_Encryption_with_KDF::~KEM_Encryption_with_KDF() = default;
234
235
0
size_t PK_Ops::KEM_Decryption_with_KDF::shared_key_length(size_t desired_shared_key_len) const {
236
0
   if(m_kdf) {
237
0
      return desired_shared_key_len;
238
0
   } else {
239
0
      return this->raw_kem_shared_key_length();
240
0
   }
241
0
}
242
243
void 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
0
                                                  std::span<const uint8_t> salt) {
247
0
   BOTAN_ARG_CHECK(salt.empty() || m_kdf, "PK_KEM_Decryptor::decrypt requires a KDF to use a salt");
248
249
0
   if(m_kdf) {
250
0
      BOTAN_ASSERT_EQUAL(
251
0
         out_shared_key.size(), desired_shared_key_len, "KDF output length and shared key length match");
252
253
0
      secure_vector<uint8_t> raw_shared(raw_kem_shared_key_length());
254
0
      this->raw_kem_decrypt(raw_shared, encapsulated_key);
255
0
      m_kdf->derive_key(out_shared_key, raw_shared, salt, {});
256
0
   } else {
257
0
      BOTAN_ASSERT_EQUAL(out_shared_key.size(), raw_kem_shared_key_length(), "Shared key has raw KEM output length");
258
0
      this->raw_kem_decrypt(out_shared_key, encapsulated_key);
259
0
   }
260
0
}
261
262
0
PK_Ops::KEM_Decryption_with_KDF::KEM_Decryption_with_KDF(std::string_view kdf) {
263
0
   if(kdf != "Raw") {
264
0
      m_kdf = KDF::create_or_throw(kdf);
265
0
   }
266
0
}
267
268
0
PK_Ops::KEM_Decryption_with_KDF::~KEM_Decryption_with_KDF() = default;
269
270
}  // namespace Botan