Coverage Report

Created: 2023-09-25 06:33

/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/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
0
AlgorithmIdentifier PK_Ops::Signature::algorithm_identifier() const {
25
0
   throw Not_Implemented("This signature scheme does not have an algorithm identifier available");
26
0
}
27
28
0
PK_Ops::Encryption_with_EME::Encryption_with_EME(std::string_view eme) : m_eme(EME::create(eme)) {}
29
30
0
size_t PK_Ops::Encryption_with_EME::max_input_bits() const {
31
0
   return 8 * m_eme->maximum_input_size(max_ptext_input_bits());
32
0
}
33
34
secure_vector<uint8_t> PK_Ops::Encryption_with_EME::encrypt(const uint8_t msg[],
35
                                                            size_t msg_len,
36
0
                                                            RandomNumberGenerator& rng) {
37
0
   const size_t max_raw = max_ptext_input_bits();
38
0
   const auto encoded = m_eme->encode(msg, msg_len, max_raw, rng);
39
0
   return raw_encrypt(encoded.data(), encoded.size(), rng);
40
0
}
41
42
0
PK_Ops::Decryption_with_EME::Decryption_with_EME(std::string_view eme) : m_eme(EME::create(eme)) {}
43
44
secure_vector<uint8_t> PK_Ops::Decryption_with_EME::decrypt(uint8_t& valid_mask,
45
                                                            const uint8_t ciphertext[],
46
0
                                                            size_t ciphertext_len) {
47
0
   const secure_vector<uint8_t> raw = raw_decrypt(ciphertext, ciphertext_len);
48
0
   return m_eme->unpad(valid_mask, raw.data(), raw.size());
49
0
}
50
51
22
PK_Ops::Key_Agreement_with_KDF::Key_Agreement_with_KDF(std::string_view kdf) {
52
22
   if(kdf != "Raw") {
53
0
      m_kdf = KDF::create_or_throw(kdf);
54
0
   }
55
22
}
56
57
secure_vector<uint8_t> PK_Ops::Key_Agreement_with_KDF::agree(
58
12
   size_t key_len, const uint8_t w[], size_t w_len, const uint8_t salt[], size_t salt_len) {
59
12
   if(salt_len > 0 && m_kdf == nullptr) {
60
0
      throw Invalid_Argument("PK_Key_Agreement::derive_key requires a KDF to use a salt");
61
0
   }
62
63
12
   secure_vector<uint8_t> z = raw_agree(w, w_len);
64
12
   if(m_kdf) {
65
0
      return m_kdf->derive_key(key_len, z, salt, salt_len);
66
0
   }
67
12
   return z;
68
12
}
69
70
namespace {
71
72
179
std::unique_ptr<HashFunction> create_signature_hash(std::string_view padding) {
73
179
   if(auto hash = HashFunction::create(padding)) {
74
0
      return hash;
75
0
   }
76
77
179
   SCAN_Name req(padding);
78
79
179
   if(req.algo_name() == "EMSA1" && req.arg_count() == 1) {
80
66
      if(auto hash = HashFunction::create(req.arg(0))) {
81
66
         return hash;
82
66
      }
83
66
   }
84
85
113
#if defined(BOTAN_HAS_RAW_HASH_FN)
86
113
   if(req.algo_name() == "Raw") {
87
113
      if(req.arg_count() == 0) {
88
113
         return std::make_unique<RawHashFunction>("Raw", 0);
89
113
      }
90
91
0
      if(req.arg_count() == 1) {
92
0
         if(auto hash = HashFunction::create(req.arg(0))) {
93
0
            return std::make_unique<RawHashFunction>(std::move(hash));
94
0
         }
95
0
      }
96
0
   }
97
0
#endif
98
99
0
   throw Algorithm_Not_Found(padding);
100
113
}
101
102
}  // namespace
103
104
PK_Ops::Signature_with_Hash::Signature_with_Hash(std::string_view hash) :
105
66
      Signature(), m_hash(create_signature_hash(hash)) {}
106
107
#if defined(BOTAN_HAS_RFC6979_GENERATOR)
108
43
std::string PK_Ops::Signature_with_Hash::rfc6979_hash_function() const {
109
43
   std::string hash = m_hash->name();
110
43
   if(hash != "Raw") {
111
43
      return hash;
112
43
   }
113
0
   return "SHA-512";
114
43
}
115
#endif
116
117
54
void PK_Ops::Signature_with_Hash::update(const uint8_t msg[], size_t msg_len) {
118
54
   m_hash->update(msg, msg_len);
119
54
}
120
121
54
secure_vector<uint8_t> PK_Ops::Signature_with_Hash::sign(RandomNumberGenerator& rng) {
122
54
   const secure_vector<uint8_t> msg = m_hash->final();
123
54
   return raw_sign(msg.data(), msg.size(), rng);
124
54
}
125
126
PK_Ops::Verification_with_Hash::Verification_with_Hash(std::string_view padding) :
127
113
      Verification(), m_hash(create_signature_hash(padding)) {}
128
129
PK_Ops::Verification_with_Hash::Verification_with_Hash(const AlgorithmIdentifier& alg_id,
130
                                                       std::string_view pk_algo,
131
0
                                                       bool allow_null_parameters) {
132
0
   const auto oid_info = split_on(alg_id.oid().to_formatted_string(), '/');
133
134
0
   if(oid_info.size() != 2 || oid_info[0] != pk_algo) {
135
0
      throw Decoding_Error(
136
0
         fmt("Unexpected AlgorithmIdentifier OID {} in association with {} key", alg_id.oid(), pk_algo));
137
0
   }
138
139
0
   if(!alg_id.parameters_are_empty()) {
140
0
      if(alg_id.parameters_are_null()) {
141
0
         if(!allow_null_parameters) {
142
0
            throw Decoding_Error(fmt("Unexpected NULL AlgorithmIdentifier parameters for {}", pk_algo));
143
0
         }
144
0
      } else {
145
0
         throw Decoding_Error(fmt("Unexpected AlgorithmIdentifier parameters for {}", pk_algo));
146
0
      }
147
0
   }
148
149
0
   m_hash = HashFunction::create_or_throw(oid_info[1]);
150
0
}
151
152
113
void PK_Ops::Verification_with_Hash::update(const uint8_t msg[], size_t msg_len) {
153
113
   m_hash->update(msg, msg_len);
154
113
}
155
156
113
bool PK_Ops::Verification_with_Hash::is_valid_signature(const uint8_t sig[], size_t sig_len) {
157
113
   const secure_vector<uint8_t> msg = m_hash->final();
158
113
   return verify(msg.data(), msg.size(), sig, sig_len);
159
113
}
160
161
0
size_t PK_Ops::KEM_Encryption_with_KDF::shared_key_length(size_t desired_shared_key_len) const {
162
0
   if(m_kdf) {
163
0
      return desired_shared_key_len;
164
0
   } else {
165
0
      return this->raw_kem_shared_key_length();
166
0
   }
167
0
}
168
169
void PK_Ops::KEM_Encryption_with_KDF::kem_encrypt(std::span<uint8_t> out_encapsulated_key,
170
                                                  std::span<uint8_t> out_shared_key,
171
                                                  RandomNumberGenerator& rng,
172
                                                  size_t desired_shared_key_len,
173
0
                                                  std::span<const uint8_t> salt) {
174
0
   BOTAN_ARG_CHECK(salt.empty() || m_kdf, "PK_KEM_Encryptor::encrypt requires a KDF to use a salt");
175
0
   BOTAN_ASSERT_NOMSG(out_encapsulated_key.size() == encapsulated_key_length());
176
177
0
   if(m_kdf) {
178
0
      BOTAN_ASSERT_EQUAL(
179
0
         out_shared_key.size(), desired_shared_key_len, "KDF output length and shared key length match");
180
181
0
      secure_vector<uint8_t> raw_shared(raw_kem_shared_key_length());
182
0
      this->raw_kem_encrypt(out_encapsulated_key, raw_shared, rng);
183
0
      m_kdf->derive_key(out_shared_key, raw_shared, salt, {});
184
0
   } else {
185
0
      BOTAN_ASSERT_EQUAL(out_shared_key.size(), raw_kem_shared_key_length(), "Shared key has raw KEM output length");
186
0
      this->raw_kem_encrypt(out_encapsulated_key, out_shared_key, rng);
187
0
   }
188
0
}
189
190
0
PK_Ops::KEM_Encryption_with_KDF::KEM_Encryption_with_KDF(std::string_view kdf) {
191
0
   if(kdf != "Raw") {
192
0
      m_kdf = KDF::create_or_throw(kdf);
193
0
   }
194
0
}
195
196
0
size_t PK_Ops::KEM_Decryption_with_KDF::shared_key_length(size_t desired_shared_key_len) const {
197
0
   if(m_kdf) {
198
0
      return desired_shared_key_len;
199
0
   } else {
200
0
      return this->raw_kem_shared_key_length();
201
0
   }
202
0
}
203
204
void PK_Ops::KEM_Decryption_with_KDF::kem_decrypt(std::span<uint8_t> out_shared_key,
205
                                                  std::span<const uint8_t> encapsulated_key,
206
                                                  size_t desired_shared_key_len,
207
0
                                                  std::span<const uint8_t> salt) {
208
0
   BOTAN_ARG_CHECK(salt.empty() || m_kdf, "PK_KEM_Decryptor::decrypt requires a KDF to use a salt");
209
210
0
   if(m_kdf) {
211
0
      BOTAN_ASSERT_EQUAL(
212
0
         out_shared_key.size(), desired_shared_key_len, "KDF output length and shared key length match");
213
214
0
      secure_vector<uint8_t> raw_shared(raw_kem_shared_key_length());
215
0
      this->raw_kem_decrypt(raw_shared, encapsulated_key);
216
0
      m_kdf->derive_key(out_shared_key, raw_shared, salt, {});
217
0
   } else {
218
0
      BOTAN_ASSERT_EQUAL(out_shared_key.size(), raw_kem_shared_key_length(), "Shared key has raw KEM output length");
219
0
      this->raw_kem_decrypt(out_shared_key, encapsulated_key);
220
0
   }
221
0
}
222
223
0
PK_Ops::KEM_Decryption_with_KDF::KEM_Decryption_with_KDF(std::string_view kdf) {
224
0
   if(kdf != "Raw") {
225
0
      m_kdf = KDF::create_or_throw(kdf);
226
0
   }
227
0
}
228
229
}  // namespace Botan