• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 16639460992

30 Jul 2025 11:40PM UTC coverage: 90.683% (-0.007%) from 90.69%
16639460992

push

github

web-flow
Merge pull request #5024 from randombit/jack/now-with-less-emsa

Remove various references to EMSA in the code and docs

99974 of 110246 relevant lines covered (90.68%)

12444599.23 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.43
/src/lib/pubkey/pk_ops.cpp
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
AlgorithmIdentifier PK_Ops::Signature::algorithm_identifier() const {
×
26
   throw Not_Implemented("This signature scheme does not have an algorithm identifier available");
×
27
}
28

29
PK_Ops::Encryption_with_EME::Encryption_with_EME(std::string_view eme) : m_eme(EME::create(eme)) {}
301✔
30

31
PK_Ops::Encryption_with_EME::~Encryption_with_EME() = default;
301✔
32

33
size_t PK_Ops::Encryption_with_EME::max_input_bits() const {
204✔
34
   return 8 * m_eme->maximum_input_size(max_ptext_input_bits());
204✔
35
}
36

37
std::vector<uint8_t> PK_Ops::Encryption_with_EME::encrypt(std::span<const uint8_t> msg, RandomNumberGenerator& rng) {
369✔
38
   const size_t max_input_bits = max_ptext_input_bits();
369✔
39
   const size_t max_input_bytes = (max_input_bits + 7) / 8;
369✔
40
   BOTAN_ARG_CHECK(msg.size() <= max_input_bytes, "Plaintext too large");
369✔
41

42
   secure_vector<uint8_t> eme_output(max_input_bits);
369✔
43
   const size_t written = m_eme->pad(eme_output, msg, max_input_bits, rng);
369✔
44
   return raw_encrypt(std::span{eme_output}.first(written), rng);
369✔
45
}
738✔
46

47
PK_Ops::Decryption_with_EME::Decryption_with_EME(std::string_view eme) : m_eme(EME::create(eme)) {}
314✔
48

49
PK_Ops::Decryption_with_EME::~Decryption_with_EME() = default;
314✔
50

51
secure_vector<uint8_t> PK_Ops::Decryption_with_EME::decrypt(uint8_t& valid_mask, std::span<const uint8_t> ctext) {
5,659✔
52
   const secure_vector<uint8_t> raw = raw_decrypt(ctext);
5,659✔
53

54
   secure_vector<uint8_t> ptext(raw.size());
5,636✔
55
   auto len = m_eme->unpad(ptext, raw);
5,636✔
56

57
   valid_mask = CT::Mask<uint8_t>::from_choice(len.has_value()).if_set_return(0xFF);
5,636✔
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));
5,636✔
70
   return ptext;
5,636✔
71
}
5,636✔
72

73
PK_Ops::Key_Agreement_with_KDF::Key_Agreement_with_KDF(std::string_view kdf) {
8,855✔
74
   if(kdf != "Raw") {
17,672✔
75
      m_kdf = KDF::create_or_throw(kdf);
38✔
76
   }
77
}
8,855✔
78

79
PK_Ops::Key_Agreement_with_KDF::~Key_Agreement_with_KDF() = default;
8,855✔
80

81
secure_vector<uint8_t> PK_Ops::Key_Agreement_with_KDF::agree(size_t key_len,
10,440✔
82
                                                             std::span<const uint8_t> other_key,
83
                                                             std::span<const uint8_t> salt) {
84
   if(!salt.empty() && m_kdf == nullptr) {
10,440✔
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());
10,440✔
89
   if(m_kdf) {
10,379✔
90
      return m_kdf->derive_key(key_len, z, salt.data(), salt.size());
108✔
91
   }
92
   return z;
10,325✔
93
}
10,379✔
94

95
namespace {
96

97
std::unique_ptr<HashFunction> create_signature_hash(std::string_view padding) {
15,493✔
98
   if(auto hash = HashFunction::create(padding)) {
15,493✔
99
      return hash;
11,116✔
100
   }
11,116✔
101

102
   SCAN_Name req(padding);
4,377✔
103

104
   if(req.algo_name() == "EMSA1" && req.arg_count() == 1) {
4,377✔
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") {
4,377✔
112
      if(req.arg_count() == 0) {
127✔
113
         return std::make_unique<RawHashFunction>("Raw", 0);
112✔
114
      }
115

116
      if(req.arg_count() == 1) {
15✔
117
         if(auto hash = HashFunction::create(req.arg(0))) {
30✔
118
            return std::make_unique<RawHashFunction>(std::move(hash));
15✔
119
         }
15✔
120
      }
121
   }
122
#endif
123

124
   throw Algorithm_Not_Found(padding);
4,250✔
125
}
4,377✔
126

127
}  // namespace
128

129
PK_Ops::Signature_with_Hash::Signature_with_Hash(std::string_view hash) :
2,327✔
130
      Signature(), m_hash(create_signature_hash(hash)) {}
2,327✔
131

132
PK_Ops::Signature_with_Hash::~Signature_with_Hash() = default;
2,327✔
133

134
#if defined(BOTAN_HAS_RFC6979_GENERATOR)
135
std::string PK_Ops::Signature_with_Hash::rfc6979_hash_function() const {
2,238✔
136
   std::string hash = m_hash->name();
2,238✔
137
   if(hash != "Raw") {
2,238✔
138
      return hash;
2,227✔
139
   }
140
   return "SHA-512";
11✔
141
}
2,238✔
142
#endif
143

144
std::string PK_Ops::Signature_with_Hash::hash_function() const {
3,822✔
145
   return m_hash->name();
3,822✔
146
}
147

148
void PK_Ops::Signature_with_Hash::update(std::span<const uint8_t> msg) {
6,138✔
149
   m_hash->update(msg);
6,138✔
150
}
6,138✔
151

152
std::vector<uint8_t> PK_Ops::Signature_with_Hash::sign(RandomNumberGenerator& rng) {
6,139✔
153
   const std::vector<uint8_t> msg = m_hash->final_stdvec();
6,139✔
154
   return raw_sign(msg, rng);
6,139✔
155
}
6,139✔
156

157
PK_Ops::Verification_with_Hash::Verification_with_Hash(std::string_view padding) :
13,166✔
158
      Verification(), m_hash(create_signature_hash(padding)) {}
13,166✔
159

160
PK_Ops::Verification_with_Hash::~Verification_with_Hash() = default;
13,436✔
161

162
std::string PK_Ops::Verification_with_Hash::hash_function() const {
4,440✔
163
   return m_hash->name();
4,440✔
164
}
165

166
PK_Ops::Verification_with_Hash::Verification_with_Hash(const AlgorithmIdentifier& alg_id,
4,561✔
167
                                                       std::string_view pk_algo,
168
                                                       bool allow_null_parameters) {
4,561✔
169
   const auto oid_info = split_on(alg_id.oid().to_formatted_string(), '/');
4,561✔
170

171
   if(oid_info.size() != 2 || oid_info[0] != pk_algo) {
4,561✔
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()) {
4,561✔
177
      if(alg_id.parameters_are_null()) {
44✔
178
         if(!allow_null_parameters) {
44✔
179
            throw Decoding_Error(fmt("Unexpected NULL AlgorithmIdentifier parameters for {}", pk_algo));
82✔
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]);
4,520✔
187
}
4,602✔
188

189
void PK_Ops::Verification_with_Hash::update(std::span<const uint8_t> msg) {
36,445✔
190
   m_hash->update(msg);
36,445✔
191
}
36,445✔
192

193
bool PK_Ops::Verification_with_Hash::is_valid_signature(std::span<const uint8_t> sig) {
36,219✔
194
   const std::vector<uint8_t> msg = m_hash->final_stdvec();
36,219✔
195
   return verify(msg, sig);
36,219✔
196
}
36,219✔
197

198
size_t PK_Ops::KEM_Encryption_with_KDF::shared_key_length(size_t desired_shared_key_len) const {
6,964✔
199
   if(m_kdf) {
6,964✔
200
      return desired_shared_key_len;
201
   } else {
202
      return this->raw_kem_shared_key_length();
1,744✔
203
   }
204
}
205

206
void PK_Ops::KEM_Encryption_with_KDF::kem_encrypt(std::span<uint8_t> out_encapsulated_key,
3,362✔
207
                                                  std::span<uint8_t> out_shared_key,
208
                                                  RandomNumberGenerator& rng,
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");
3,362✔
212
   BOTAN_ASSERT_NOMSG(out_encapsulated_key.size() == encapsulated_key_length());
3,362✔
213

214
   if(m_kdf) {
3,362✔
215
      BOTAN_ASSERT_EQUAL(
2,604✔
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());
2,604✔
219
      this->raw_kem_encrypt(out_encapsulated_key, raw_shared, rng);
2,604✔
220
      m_kdf->derive_key(out_shared_key, raw_shared, salt, {});
5,208✔
221
   } else {
2,604✔
222
      BOTAN_ASSERT_EQUAL(out_shared_key.size(), raw_kem_shared_key_length(), "Shared key has raw KEM output length");
758✔
223
      this->raw_kem_encrypt(out_encapsulated_key, out_shared_key, rng);
758✔
224
   }
225
}
3,360✔
226

227
PK_Ops::KEM_Encryption_with_KDF::KEM_Encryption_with_KDF(std::string_view kdf) {
844✔
228
   if(kdf != "Raw") {
1,579✔
229
      m_kdf = KDF::create_or_throw(kdf);
109✔
230
   }
231
}
844✔
232

233
PK_Ops::KEM_Encryption_with_KDF::~KEM_Encryption_with_KDF() = default;
844✔
234

235
size_t PK_Ops::KEM_Decryption_with_KDF::shared_key_length(size_t desired_shared_key_len) const {
7,114✔
236
   if(m_kdf) {
7,114✔
237
      return desired_shared_key_len;
238
   } else {
239
      return this->raw_kem_shared_key_length();
1,894✔
240
   }
241
}
242

243
void PK_Ops::KEM_Decryption_with_KDF::kem_decrypt(std::span<uint8_t> out_shared_key,
3,431✔
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");
3,431✔
248

249
   if(m_kdf) {
3,431✔
250
      BOTAN_ASSERT_EQUAL(
2,604✔
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());
2,604✔
254
      this->raw_kem_decrypt(raw_shared, encapsulated_key);
2,604✔
255
      m_kdf->derive_key(out_shared_key, raw_shared, salt, {});
5,208✔
256
   } else {
2,604✔
257
      BOTAN_ASSERT_EQUAL(out_shared_key.size(), raw_kem_shared_key_length(), "Shared key has raw KEM output length");
827✔
258
      this->raw_kem_decrypt(out_shared_key, encapsulated_key);
827✔
259
   }
260
}
3,409✔
261

262
PK_Ops::KEM_Decryption_with_KDF::KEM_Decryption_with_KDF(std::string_view kdf) {
782✔
263
   if(kdf != "Raw") {
1,455✔
264
      m_kdf = KDF::create_or_throw(kdf);
109✔
265
   }
266
}
782✔
267

268
PK_Ops::KEM_Decryption_with_KDF::~KEM_Decryption_with_KDF() = default;
782✔
269

270
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc