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

randombit / botan / 12195401256

06 Dec 2024 08:21AM UTC coverage: 91.257% (-0.005%) from 91.262%
12195401256

push

github

web-flow
Merge pull request #4467 from randombit/jack/ref-4465

Add a set of test vectors for odd sized RSA keys

93389 of 102336 relevant lines covered (91.26%)

11818338.79 hits per line

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

95.24
/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/rng.h>
12
#include <botan/internal/bit_ops.h>
13
#include <botan/internal/fmt.h>
14
#include <botan/internal/parsing.h>
15
#include <botan/internal/scan_name.h>
16
#include <sstream>
17

18
#if defined(BOTAN_HAS_RAW_HASH_FN)
19
   #include <botan/internal/raw_hash.h>
20
#endif
21

22
namespace Botan {
23

24
AlgorithmIdentifier PK_Ops::Signature::algorithm_identifier() const {
×
25
   throw Not_Implemented("This signature scheme does not have an algorithm identifier available");
×
26
}
27

28
PK_Ops::Encryption_with_EME::Encryption_with_EME(std::string_view eme) : m_eme(EME::create(eme)) {}
273✔
29

30
size_t PK_Ops::Encryption_with_EME::max_input_bits() const {
204✔
31
   return 8 * m_eme->maximum_input_size(max_ptext_input_bits());
204✔
32
}
33

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

39
   secure_vector<uint8_t> eme_output(max_input_bits);
341✔
40
   const size_t written = m_eme->pad(eme_output, msg, max_input_bits, rng);
341✔
41
   return raw_encrypt(std::span{eme_output}.first(written), rng);
341✔
42
}
682✔
43

44
PK_Ops::Decryption_with_EME::Decryption_with_EME(std::string_view eme) : m_eme(EME::create(eme)) {}
312✔
45

46
secure_vector<uint8_t> PK_Ops::Decryption_with_EME::decrypt(uint8_t& valid_mask, std::span<const uint8_t> ctext) {
5,335✔
47
   const secure_vector<uint8_t> raw = raw_decrypt(ctext);
5,335✔
48

49
   secure_vector<uint8_t> ptext(raw.size());
5,320✔
50
   auto len = m_eme->unpad(ptext, raw);
5,320✔
51

52
   valid_mask = CT::Mask<uint8_t>::from_choice(len.has_value()).if_set_return(0xFF);
5,320✔
53

54
   /*
55
   This is potentially not const time, depending on how std::vector is
56
   implemented. But since we are always reducing length, it should
57
   just amount to setting the member var holding the length. Resizing
58
   downwards is guaranteed to not change the capacity, and since we
59
   set ctext to the maximum possible size (equal to the raw input) we
60
   know that this is always, if anything, resizing smaller than the
61
   capacity, so no reallocation occurs.
62
   */
63

64
   ptext.resize(len.value_or(0));
5,320✔
65
   return ptext;
5,320✔
66
}
5,320✔
67

68
PK_Ops::Key_Agreement_with_KDF::Key_Agreement_with_KDF(std::string_view kdf) {
8,836✔
69
   if(kdf != "Raw") {
17,634✔
70
      m_kdf = KDF::create_or_throw(kdf);
38✔
71
   }
72
}
8,836✔
73

74
secure_vector<uint8_t> PK_Ops::Key_Agreement_with_KDF::agree(size_t key_len,
10,414✔
75
                                                             std::span<const uint8_t> other_key,
76
                                                             std::span<const uint8_t> salt) {
77
   if(!salt.empty() && m_kdf == nullptr) {
10,414✔
78
      throw Invalid_Argument("PK_Key_Agreement::derive_key requires a KDF to use a salt");
×
79
   }
80

81
   secure_vector<uint8_t> z = raw_agree(other_key.data(), other_key.size());
10,414✔
82
   if(m_kdf) {
10,379✔
83
      return m_kdf->derive_key(key_len, z, salt.data(), salt.size());
10,379✔
84
   }
85
   return z;
10,331✔
86
}
10,379✔
87

88
namespace {
89

90
std::unique_ptr<HashFunction> create_signature_hash(std::string_view padding) {
13,823✔
91
   if(auto hash = HashFunction::create(padding)) {
13,823✔
92
      return hash;
9,443✔
93
   }
9,443✔
94

95
   SCAN_Name req(padding);
4,380✔
96

97
   if(req.algo_name() == "EMSA1" && req.arg_count() == 1) {
4,380✔
98
      if(auto hash = HashFunction::create(req.arg(0))) {
10✔
99
         return hash;
5✔
100
      }
5✔
101
   }
102

103
#if defined(BOTAN_HAS_RAW_HASH_FN)
104
   if(req.algo_name() == "Raw") {
4,375✔
105
      if(req.arg_count() == 0) {
125✔
106
         return std::make_unique<RawHashFunction>("Raw", 0);
110✔
107
      }
108

109
      if(req.arg_count() == 1) {
15✔
110
         if(auto hash = HashFunction::create(req.arg(0))) {
30✔
111
            return std::make_unique<RawHashFunction>(std::move(hash));
15✔
112
         }
15✔
113
      }
114
   }
115
#endif
116

117
   throw Algorithm_Not_Found(padding);
4,250✔
118
}
4,380✔
119

120
}  // namespace
121

122
PK_Ops::Signature_with_Hash::Signature_with_Hash(std::string_view hash) :
746✔
123
      Signature(), m_hash(create_signature_hash(hash)) {}
746✔
124

125
#if defined(BOTAN_HAS_RFC6979_GENERATOR)
126
std::string PK_Ops::Signature_with_Hash::rfc6979_hash_function() const {
657✔
127
   std::string hash = m_hash->name();
657✔
128
   if(hash != "Raw") {
657✔
129
      return hash;
647✔
130
   }
131
   return "SHA-512";
10✔
132
}
657✔
133
#endif
134

135
void PK_Ops::Signature_with_Hash::update(std::span<const uint8_t> msg) {
3,326✔
136
   m_hash->update(msg);
3,326✔
137
}
3,326✔
138

139
std::vector<uint8_t> PK_Ops::Signature_with_Hash::sign(RandomNumberGenerator& rng) {
3,327✔
140
   const std::vector<uint8_t> msg = m_hash->final_stdvec();
3,327✔
141
   return raw_sign(msg, rng);
3,327✔
142
}
3,327✔
143

144
PK_Ops::Verification_with_Hash::Verification_with_Hash(std::string_view padding) :
13,077✔
145
      Verification(), m_hash(create_signature_hash(padding)) {}
13,077✔
146

147
PK_Ops::Verification_with_Hash::Verification_with_Hash(const AlgorithmIdentifier& alg_id,
2,947✔
148
                                                       std::string_view pk_algo,
149
                                                       bool allow_null_parameters) {
2,947✔
150
   const auto oid_info = split_on(alg_id.oid().to_formatted_string(), '/');
2,947✔
151

152
   if(oid_info.size() != 2 || oid_info[0] != pk_algo) {
2,947✔
153
      throw Decoding_Error(
×
154
         fmt("Unexpected AlgorithmIdentifier OID {} in association with {} key", alg_id.oid(), pk_algo));
×
155
   }
156

157
   if(!alg_id.parameters_are_empty()) {
2,947✔
158
      if(alg_id.parameters_are_null()) {
44✔
159
         if(!allow_null_parameters) {
44✔
160
            throw Decoding_Error(fmt("Unexpected NULL AlgorithmIdentifier parameters for {}", pk_algo));
82✔
161
         }
162
      } else {
163
         throw Decoding_Error(fmt("Unexpected AlgorithmIdentifier parameters for {}", pk_algo));
×
164
      }
165
   }
166

167
   m_hash = HashFunction::create_or_throw(oid_info[1]);
2,906✔
168
}
2,988✔
169

170
void PK_Ops::Verification_with_Hash::update(std::span<const uint8_t> msg) {
34,717✔
171
   m_hash->update(msg);
34,717✔
172
}
34,717✔
173

174
bool PK_Ops::Verification_with_Hash::is_valid_signature(std::span<const uint8_t> sig) {
34,495✔
175
   const std::vector<uint8_t> msg = m_hash->final_stdvec();
34,495✔
176
   return verify(msg, sig);
34,495✔
177
}
34,495✔
178

179
size_t PK_Ops::KEM_Encryption_with_KDF::shared_key_length(size_t desired_shared_key_len) const {
6,802✔
180
   if(m_kdf) {
6,802✔
181
      return desired_shared_key_len;
182
   } else {
183
      return this->raw_kem_shared_key_length();
1,566✔
184
   }
185
}
186

187
void PK_Ops::KEM_Encryption_with_KDF::kem_encrypt(std::span<uint8_t> out_encapsulated_key,
3,357✔
188
                                                  std::span<uint8_t> out_shared_key,
189
                                                  RandomNumberGenerator& rng,
190
                                                  size_t desired_shared_key_len,
191
                                                  std::span<const uint8_t> salt) {
192
   BOTAN_ARG_CHECK(salt.empty() || m_kdf, "PK_KEM_Encryptor::encrypt requires a KDF to use a salt");
3,357✔
193
   BOTAN_ASSERT_NOMSG(out_encapsulated_key.size() == encapsulated_key_length());
3,357✔
194

195
   if(m_kdf) {
3,357✔
196
      BOTAN_ASSERT_EQUAL(
2,612✔
197
         out_shared_key.size(), desired_shared_key_len, "KDF output length and shared key length match");
198

199
      secure_vector<uint8_t> raw_shared(raw_kem_shared_key_length());
2,612✔
200
      this->raw_kem_encrypt(out_encapsulated_key, raw_shared, rng);
2,612✔
201
      m_kdf->derive_key(out_shared_key, raw_shared, salt, {});
5,224✔
202
   } else {
2,612✔
203
      BOTAN_ASSERT_EQUAL(out_shared_key.size(), raw_kem_shared_key_length(), "Shared key has raw KEM output length");
745✔
204
      this->raw_kem_encrypt(out_encapsulated_key, out_shared_key, rng);
745✔
205
   }
206
}
3,352✔
207

208
PK_Ops::KEM_Encryption_with_KDF::KEM_Encryption_with_KDF(std::string_view kdf) {
832✔
209
   if(kdf != "Raw") {
1,555✔
210
      m_kdf = KDF::create_or_throw(kdf);
109✔
211
   }
212
}
832✔
213

214
size_t PK_Ops::KEM_Decryption_with_KDF::shared_key_length(size_t desired_shared_key_len) const {
6,952✔
215
   if(m_kdf) {
6,952✔
216
      return desired_shared_key_len;
217
   } else {
218
      return this->raw_kem_shared_key_length();
1,716✔
219
   }
220
}
221

222
void PK_Ops::KEM_Decryption_with_KDF::kem_decrypt(std::span<uint8_t> out_shared_key,
3,428✔
223
                                                  std::span<const uint8_t> encapsulated_key,
224
                                                  size_t desired_shared_key_len,
225
                                                  std::span<const uint8_t> salt) {
226
   BOTAN_ARG_CHECK(salt.empty() || m_kdf, "PK_KEM_Decryptor::decrypt requires a KDF to use a salt");
3,428✔
227

228
   if(m_kdf) {
3,428✔
229
      BOTAN_ASSERT_EQUAL(
2,612✔
230
         out_shared_key.size(), desired_shared_key_len, "KDF output length and shared key length match");
231

232
      secure_vector<uint8_t> raw_shared(raw_kem_shared_key_length());
2,612✔
233
      this->raw_kem_decrypt(raw_shared, encapsulated_key);
2,612✔
234
      m_kdf->derive_key(out_shared_key, raw_shared, salt, {});
5,224✔
235
   } else {
2,612✔
236
      BOTAN_ASSERT_EQUAL(out_shared_key.size(), raw_kem_shared_key_length(), "Shared key has raw KEM output length");
816✔
237
      this->raw_kem_decrypt(out_shared_key, encapsulated_key);
816✔
238
   }
239
}
3,403✔
240

241
PK_Ops::KEM_Decryption_with_KDF::KEM_Decryption_with_KDF(std::string_view kdf) {
780✔
242
   if(kdf != "Raw") {
1,451✔
243
      m_kdf = KDF::create_or_throw(kdf);
109✔
244
   }
245
}
780✔
246

247
}  // 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