Botan 3.13.0
Crypto and TLS for C&
pbes2.cpp
Go to the documentation of this file.
1/*
2* PKCS #5 PBES2
3* (C) 1999-2008,2014,2021 Jack Lloyd
4* (C) 2018 Ribose Inc
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#include <botan/internal/pbes2.h>
10
11#include <botan/asn1_obj.h>
12#include <botan/ber_dec.h>
13#include <botan/cipher_mode.h>
14#include <botan/der_enc.h>
15#include <botan/pwdhash.h>
16#include <botan/rng.h>
17#include <botan/internal/bit_ops.h>
18#include <botan/internal/fmt.h>
19#include <botan/internal/parsing.h>
20
21namespace Botan {
22
23namespace {
24
25class Pbes2KdfParameters {
26 public:
27 virtual ~Pbes2KdfParameters() = default;
28 Pbes2KdfParameters(const Pbes2KdfParameters& other) = delete;
29 Pbes2KdfParameters(Pbes2KdfParameters&& other) = delete;
30 Pbes2KdfParameters& operator=(const Pbes2KdfParameters& other) = delete;
31 Pbes2KdfParameters& operator=(Pbes2KdfParameters&& other) = delete;
32
33 static std::unique_ptr<Pbes2KdfParameters> decode(const AlgorithmIdentifier& alg_id);
34
35 static std::unique_ptr<Pbes2KdfParameters> tune(std::string_view digest,
36 RandomNumberGenerator& rng,
37 size_t key_length,
38 size_t* msec_in_iterations_out,
39 size_t iterations_if_msec_null);
40
41 secure_vector<uint8_t> derive_key(std::string_view passphrase, size_t default_key_size) const;
42
43 virtual AlgorithmIdentifier algorithm_identifier(bool include_key_length) const = 0;
44
45 protected:
46 static constexpr size_t DefaultSaltBytes = 16;
47
48 const PasswordHash& pwdhash() const { return *m_pwdhash; }
49
50 std::optional<size_t> key_length() const { return m_key_length; }
51
52 std::span<const uint8_t> salt() const { return m_salt; }
53
54 Pbes2KdfParameters(std::vector<uint8_t> salt,
55 std::optional<size_t> key_length,
56 std::unique_ptr<PasswordHash> pwdhash) :
57 m_salt(std::move(salt)), m_key_length(key_length), m_pwdhash(std::move(pwdhash)) {}
58
59 static std::vector<uint8_t> generate_salt(RandomNumberGenerator& rng) {
60 return rng.random_vec<std::vector<uint8_t>>(DefaultSaltBytes);
61 }
62
63 static void validate_pbes2_params(size_t salt_len, std::optional<size_t> key_length) {
64 if(key_length && (key_length.value() < 8 || key_length.value() >= 256)) {
65 throw Decoding_Error(fmt("PBES2: Encoded key length ({}) is invalid", key_length.value()));
66 }
67 if(salt_len < 8) {
68 throw Decoding_Error("PBES2: Encoded salt is too small");
69 }
70 }
71
72 private:
73 std::vector<uint8_t> m_salt;
74 std::optional<size_t> m_key_length;
75 std::unique_ptr<PasswordHash> m_pwdhash;
76};
77
78class Pbes2Pbkdf2Parameters final : public Pbes2KdfParameters {
79 public:
80 static std::unique_ptr<Pbes2Pbkdf2Parameters> decode(const AlgorithmIdentifier& kdf_algo);
81
82 static std::unique_ptr<Pbes2Pbkdf2Parameters> tune(std::string_view digest,
83 RandomNumberGenerator& rng,
84 size_t key_length,
85 size_t* msec_in_iterations_out,
86 size_t iterations_if_msec_null);
87
88 Pbes2Pbkdf2Parameters(std::vector<uint8_t> salt,
89 std::optional<size_t> key_length,
90 std::unique_ptr<PasswordHash> pwdhash,
91 std::string prf) :
92 Pbes2KdfParameters(std::move(salt), key_length, std::move(pwdhash)), m_prf(std::move(prf)) {}
93
94 AlgorithmIdentifier algorithm_identifier(bool include_key_length) const override;
95
96 private:
97 static void validate_params(size_t iterations);
98
99 std::string m_prf;
100};
101
102class Pbes2ScryptParameters final : public Pbes2KdfParameters {
103 public:
104 static std::unique_ptr<Pbes2ScryptParameters> decode(const AlgorithmIdentifier& kdf_algo);
105
106 static std::unique_ptr<Pbes2ScryptParameters> tune(RandomNumberGenerator& rng,
107 size_t key_length,
108 size_t* msec_in_iterations_out,
109 size_t iterations_if_msec_null);
110
111 Pbes2ScryptParameters(std::vector<uint8_t> salt,
112 std::optional<size_t> key_length,
113 std::unique_ptr<PasswordHash> pwdhash) :
114 Pbes2KdfParameters(std::move(salt), key_length, std::move(pwdhash)) {}
115
116 AlgorithmIdentifier algorithm_identifier(bool include_key_length) const override;
117
118 private:
119 static void validate_params(size_t N, size_t r, size_t p);
120};
121
122/* Dispatching */
123
124secure_vector<uint8_t> Pbes2KdfParameters::derive_key(std::string_view passphrase, size_t default_key_size) const {
125 const size_t kl = m_key_length.value_or(default_key_size);
126 secure_vector<uint8_t> key(kl);
127 m_pwdhash->hash(key, passphrase, m_salt);
128 return key;
129}
130
131std::unique_ptr<Pbes2KdfParameters> Pbes2KdfParameters::tune(std::string_view digest,
132 RandomNumberGenerator& rng,
133 size_t key_length,
134 size_t* msec_in_iterations_out,
135 size_t iterations_if_msec_null) {
136 if(digest == "Scrypt") {
137 return Pbes2ScryptParameters::tune(rng, key_length, msec_in_iterations_out, iterations_if_msec_null);
138 } else {
139 return Pbes2Pbkdf2Parameters::tune(digest, rng, key_length, msec_in_iterations_out, iterations_if_msec_null);
140 }
141}
142
143std::unique_ptr<Pbes2KdfParameters> Pbes2KdfParameters::decode(const AlgorithmIdentifier& kdf_algo) {
144 if(kdf_algo.oid() == OID::from_string("PKCS5.PBKDF2")) {
145 return Pbes2Pbkdf2Parameters::decode(kdf_algo);
146 } else if(kdf_algo.oid() == OID::from_string("Scrypt")) {
147 return Pbes2ScryptParameters::decode(kdf_algo);
148 } else {
149 throw Decoding_Error(fmt("PBES2 unknown or unhandled KDF algorithm '{}'", kdf_algo.oid()));
150 }
151}
152
153/* PBES2 PBKDF2 handling */
154
155std::unique_ptr<Pbes2Pbkdf2Parameters> Pbes2Pbkdf2Parameters::tune(std::string_view digest,
156 RandomNumberGenerator& rng,
157 size_t key_length,
158 size_t* msec_in_iterations_out,
159 size_t iterations_if_msec_null) {
160 const std::string prf = fmt("HMAC({})", digest);
161
162 auto pwhash_fam = PasswordHashFamily::create(fmt("PBKDF2({})", prf));
163 if(!pwhash_fam) {
164 throw Invalid_Argument(fmt("Unknown password hash digest {}", digest));
165 }
166
167 std::unique_ptr<PasswordHash> pwhash;
168 if(msec_in_iterations_out != nullptr) {
169 pwhash = pwhash_fam->tune_params(key_length, *msec_in_iterations_out);
170 *msec_in_iterations_out = pwhash->iterations();
171 } else {
172 pwhash = pwhash_fam->from_iterations(iterations_if_msec_null);
173 }
174
175 // Ensure we will accept these same parameters when decoding
176 validate_params(pwhash->iterations());
177
178 return std::make_unique<Pbes2Pbkdf2Parameters>(generate_salt(rng), key_length, std::move(pwhash), prf);
179}
180
181//static
182void Pbes2Pbkdf2Parameters::validate_params(size_t iterations) {
183 // NSS, AWS-LC, and BoringSSL all allow up to exactly 100 million for this operation
184 constexpr size_t MaximumPbes2Pbkdf2Iterations = 100'000'000;
185
186 if(iterations == 0 || iterations > MaximumPbes2Pbkdf2Iterations) {
187 throw Decoding_Error(fmt("PBES2: Invalid or unacceptable PBKDF2 iteration count ({})", iterations));
188 }
189}
190
191std::unique_ptr<Pbes2Pbkdf2Parameters> Pbes2Pbkdf2Parameters::decode(const AlgorithmIdentifier& kdf_algo) {
192 std::vector<uint8_t> salt;
193 size_t iterations = 0;
194 std::optional<size_t> key_length;
195
196 AlgorithmIdentifier prf_algo;
197 BER_Decoder(kdf_algo.parameters(), BER_Decoder::Limits::DER())
198 .start_sequence()
199 .decode(salt, ASN1_Type::OctetString)
200 .decode(iterations)
201 .decode_optional(key_length, ASN1_Type::Integer, ASN1_Class::Universal)
202 .decode_optional(prf_algo,
203 ASN1_Type::Sequence,
204 ASN1_Class::Constructed,
205 AlgorithmIdentifier("HMAC(SHA-1)", AlgorithmIdentifier::USE_NULL_PARAM))
206 .end_cons()
207 .verify_end();
208
209 validate_pbes2_params(salt.size(), key_length);
210 validate_params(iterations);
211
212 const std::string prf = [&]() {
213 if(const auto name = prf_algo.oid().registered_name()) {
214 if(name->starts_with("HMAC")) {
215 return *name;
216 }
217 }
218
219 throw Decoding_Error(fmt("Unknown PBES2 PRF '{}'", prf_algo.oid()));
220 }();
221
222 // RFC 8018 A.2 defines the PBKDF2 PRFs with NULL parameters; accept NULL or
223 // absent and reject any other parameter encoding rather than ignoring it.
224 if(!prf_algo.parameters_are_null_or_empty()) {
225 throw Decoding_Error("PBES2 PRF AlgorithmIdentifier has unexpected parameters");
226 }
227
228 auto pbkdf_fam = PasswordHashFamily::create_or_throw(fmt("PBKDF2({})", prf));
229 auto pwdhash = pbkdf_fam->from_params(iterations);
230
231 return std::make_unique<Pbes2Pbkdf2Parameters>(std::move(salt), key_length, std::move(pwdhash), prf);
232}
233
234AlgorithmIdentifier Pbes2Pbkdf2Parameters::algorithm_identifier(bool include_key_length) const {
235 std::vector<uint8_t> params;
236 DER_Encoder(params)
237 .start_sequence()
238 .encode(salt(), ASN1_Type::OctetString)
239 .encode(pwdhash().iterations())
240 .encode_if(include_key_length && key_length().has_value(), key_length().value_or(0))
241 .encode_if(m_prf != "HMAC(SHA-1)", AlgorithmIdentifier(m_prf, AlgorithmIdentifier::USE_NULL_PARAM))
242 .end_cons();
243 return AlgorithmIdentifier("PKCS5.PBKDF2", params);
244}
245
246/* PBES2 Scrypt handling */
247
248std::unique_ptr<Pbes2ScryptParameters> Pbes2ScryptParameters::tune(RandomNumberGenerator& rng,
249 size_t key_length,
250 size_t* msec_in_iterations_out,
251 size_t iterations_if_msec_null) {
252 auto pwhash_fam = PasswordHashFamily::create_or_throw("Scrypt");
253
254 std::unique_ptr<PasswordHash> pwhash;
255 if(msec_in_iterations_out != nullptr) {
256 pwhash = pwhash_fam->tune_params(key_length, *msec_in_iterations_out);
257 *msec_in_iterations_out = 0;
258 } else {
259 pwhash = pwhash_fam->from_iterations(iterations_if_msec_null);
260 }
261
262 // Ensure we will accept these same parameters when decoding
263 validate_params(pwhash->memory_param(), pwhash->iterations(), pwhash->parallelism());
264
265 return std::make_unique<Pbes2ScryptParameters>(generate_salt(rng), key_length, std::move(pwhash));
266}
267
268//static
269void Pbes2ScryptParameters::validate_params(size_t N, size_t r, size_t p) {
270 if(N <= 1 || N > 4194304 || !is_power_of_2(N)) {
271 throw Decoding_Error(fmt("PBES2: Invalid or unacceptable Scrypt parameter N ({})", N));
272 }
273 if(r == 0 || r > 64) {
274 throw Decoding_Error(fmt("PBES2: Invalid or unacceptable Scrypt parameter r ({})", r));
275 }
276 if(p == 0 || p >= 1024) {
277 throw Decoding_Error(fmt("PBES2: Invalid or unacceptable Scrypt parameter p ({})", p));
278 }
279
280 /*
281 * Practically speaking this work limit aligns relatively closely to the 100 million
282 * iteration limit applied in PBES2 and PKCS12
283 */
284 const uint64_t scrypt_work = uint64_t(N) * r * p;
285 constexpr uint64_t MaximumPbes2ScryptWork = (1 << 26);
286
287 if(scrypt_work > MaximumPbes2ScryptWork) {
288 throw Decoding_Error(fmt("PBES2: Invalid or unacceptable Scrypt parameters N={} r={} p={}", N, r, p));
289 }
290}
291
292std::unique_ptr<Pbes2ScryptParameters> Pbes2ScryptParameters::decode(const AlgorithmIdentifier& kdf_algo) {
293 std::vector<uint8_t> salt;
294 size_t N = 0;
295 size_t r = 0;
296 size_t p = 0;
297 std::optional<size_t> key_length;
298
299 BER_Decoder(kdf_algo.parameters(), BER_Decoder::Limits::DER())
300 .start_sequence()
301 .decode(salt, ASN1_Type::OctetString)
302 .decode(N)
303 .decode(r)
304 .decode(p)
305 .decode_optional(key_length, ASN1_Type::Integer, ASN1_Class::Universal)
306 .end_cons()
307 .verify_end();
308
309 validate_pbes2_params(salt.size(), key_length);
310 validate_params(N, r, p);
311
312 auto pwdhash_fam = PasswordHashFamily::create_or_throw("Scrypt");
313 auto pwdhash = pwdhash_fam->from_params(N, r, p);
314
315 return std::make_unique<Pbes2ScryptParameters>(std::move(salt), key_length, std::move(pwdhash));
316}
317
318AlgorithmIdentifier Pbes2ScryptParameters::algorithm_identifier(bool include_key_length) const {
319 std::vector<uint8_t> params;
320 DER_Encoder(params)
321 .start_sequence()
322 .encode(salt(), ASN1_Type::OctetString)
323 .encode(pwdhash().memory_param())
324 .encode(pwdhash().iterations())
325 .encode(pwdhash().parallelism())
326 .encode_if(include_key_length && key_length().has_value(), key_length().value_or(0))
327 .end_cons();
328 return AlgorithmIdentifier(OID::from_string("Scrypt"), params);
329}
330
331bool known_pbes_cipher_mode(std::string_view mode) {
332 return (mode == "CBC" || mode == "GCM" || mode == "SIV");
333}
334
335/*
336* PKCS#5 v2.0 PBE Encryption
337*/
338std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbes2_encrypt_shared(std::span<const uint8_t> key_bits,
339 std::string_view passphrase,
340 size_t* msec_in_iterations_out,
341 size_t iterations_if_msec_null,
342 std::string_view cipher,
343 std::string_view prf,
344 RandomNumberGenerator& rng) {
346
347 const auto cipher_spec = split_on(cipher, '/');
348
349 if(cipher_spec.size() != 2 || !known_pbes_cipher_mode(cipher_spec[1]) || !enc) {
350 throw Encoding_Error(fmt("PBES2: Invalid or unavailable cipher '{}'", cipher));
351 }
352
353 const size_t key_length = enc->key_spec().maximum_keylength();
354
355 const auto iv = rng.random_vec<std::vector<uint8_t>>(enc->default_nonce_length());
356
357 const bool include_key_length_in_struct = enc->key_spec().minimum_keylength() != enc->key_spec().maximum_keylength();
358
359 auto kdf_params = Pbes2KdfParameters::tune(prf, rng, key_length, msec_in_iterations_out, iterations_if_msec_null);
360 const auto derived_key = kdf_params->derive_key(passphrase, key_length);
361 const auto kdf_algo = kdf_params->algorithm_identifier(include_key_length_in_struct);
362
363 enc->set_key(derived_key);
364 enc->start(iv);
365 secure_vector<uint8_t> ctext(key_bits.begin(), key_bits.end());
366 enc->finish(ctext);
367
368 std::vector<uint8_t> encoded_iv;
369 DER_Encoder(encoded_iv).encode(iv, ASN1_Type::OctetString);
370
371 std::vector<uint8_t> pbes2_params;
372 DER_Encoder(pbes2_params)
373 .start_sequence()
374 .encode(kdf_algo)
375 .encode(AlgorithmIdentifier(cipher, encoded_iv))
376 .end_cons();
377
378 const AlgorithmIdentifier id(OID::from_string("PBE-PKCS5v20"), pbes2_params);
379
380 return std::make_pair(id, unlock(ctext));
381}
382
383} // namespace
384
385std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbes2_encrypt(std::span<const uint8_t> key_bits,
386 std::string_view passphrase,
387 std::chrono::milliseconds msec,
388 std::string_view cipher,
389 std::string_view digest,
391 size_t msec_in_iterations_out = static_cast<size_t>(msec.count());
392 return pbes2_encrypt_shared(key_bits, passphrase, &msec_in_iterations_out, 0, cipher, digest, rng);
393 // return value msec_in_iterations_out discarded
394}
395
396std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbes2_encrypt_msec(std::span<const uint8_t> key_bits,
397 std::string_view passphrase,
398 std::chrono::milliseconds msec,
399 size_t* out_iterations_if_nonnull,
400 std::string_view cipher,
401 std::string_view digest,
403 size_t msec_in_iterations_out = static_cast<size_t>(msec.count());
404
405 auto ret = pbes2_encrypt_shared(key_bits, passphrase, &msec_in_iterations_out, 0, cipher, digest, rng);
406
407 if(out_iterations_if_nonnull != nullptr) {
408 *out_iterations_if_nonnull = msec_in_iterations_out;
409 }
410
411 return ret;
412}
413
414std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbes2_encrypt_iter(std::span<const uint8_t> key_bits,
415 std::string_view passphrase,
416 size_t pbkdf_iter,
417 std::string_view cipher,
418 std::string_view digest,
420 return pbes2_encrypt_shared(key_bits, passphrase, nullptr, pbkdf_iter, cipher, digest, rng);
421}
422
423secure_vector<uint8_t> pbes2_decrypt(std::span<const uint8_t> key_bits,
424 std::string_view passphrase,
425 const std::vector<uint8_t>& params) {
426 AlgorithmIdentifier kdf_algo;
427 AlgorithmIdentifier enc_algo;
428
431 .decode(kdf_algo)
432 .decode(enc_algo)
433 .end_cons()
434 .verify_end();
435
436 const std::string cipher = [&]() -> std::string {
437 if(const auto name = enc_algo.oid().registered_name()) {
438 const auto cipher_spec = split_on(*name, '/');
439 if(cipher_spec.size() == 2 && known_pbes_cipher_mode(cipher_spec[1])) {
440 return *name;
441 }
442 }
443
444 throw Decoding_Error(fmt("PBES2: Unknown/invalid cipher OID {}", enc_algo.oid()));
445 }();
446
447 std::vector<uint8_t> iv;
449
451 if(!dec) {
452 throw Decoding_Error(fmt("PBES2 cannot decrypt due to unavailable cipher '{}'", cipher));
453 }
454
455 // The cipher parameters carry the IV (RFC 8018 B.2). Require the length be the
456 // expected value; any other length has undocumented semantics.
457 if(iv.size() != dec->default_nonce_length()) {
458 throw Decoding_Error("PBES2 cipher AlgorithmIdentifier has invalid IV length");
459 }
460
461 const size_t default_key_size = dec->key_spec().maximum_keylength();
462 auto pbkdf = Pbes2KdfParameters::decode(kdf_algo);
463 dec->set_key(pbkdf->derive_key(passphrase, default_key_size));
464
465 dec->start(iv);
466
467 secure_vector<uint8_t> buf(key_bits.begin(), key_bits.end());
468 dec->finish(buf);
469
470 return buf;
471}
472
473} // namespace Botan
const std::vector< uint8_t > & parameters() const
Definition asn1_obj.h:693
const OID & oid() const
Definition asn1_obj.h:688
static Limits DER()
Definition ber_dec.h:42
BER_Decoder & decode(bool &out)
Definition ber_dec.h:358
BER_Decoder & verify_end()
Definition ber_dec.cpp:471
BER_Decoder & end_cons()
Definition ber_dec.cpp:630
BER_Decoder start_sequence()
Definition ber_dec.h:275
static std::unique_ptr< Cipher_Mode > create(std::string_view algo, Cipher_Dir direction, std::string_view provider="")
std::optional< std::string > registered_name() const
Definition asn1_oid.cpp:149
static OID from_string(std::string_view str)
Definition asn1_oid.cpp:80
secure_vector< uint8_t > decode(DataSource &source, std::string &label)
Definition pem.cpp:62
BOTAN_FORCE_INLINE constexpr bool is_power_of_2(T arg)
Definition bit_ops.h:62
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:141
std::pair< AlgorithmIdentifier, std::vector< uint8_t > > pbes2_encrypt_iter(std::span< const uint8_t > key_bits, std::string_view passphrase, size_t pbkdf_iter, std::string_view cipher, std::string_view digest, RandomNumberGenerator &rng)
Definition pbes2.cpp:414
secure_vector< uint8_t > pbes2_decrypt(std::span< const uint8_t > key_bits, std::string_view passphrase, const std::vector< uint8_t > &params)
Definition pbes2.cpp:423
std::vector< T > unlock(const secure_vector< T > &in)
Definition secmem.h:155
std::pair< AlgorithmIdentifier, std::vector< uint8_t > > pbes2_encrypt_msec(std::span< const uint8_t > key_bits, std::string_view passphrase, std::chrono::milliseconds msec, size_t *out_iterations_if_nonnull, std::string_view cipher, std::string_view digest, RandomNumberGenerator &rng)
Definition pbes2.cpp:396
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:128
std::pair< AlgorithmIdentifier, std::vector< uint8_t > > pbes2_encrypt(std::span< const uint8_t > key_bits, std::string_view passphrase, std::chrono::milliseconds msec, std::string_view cipher, std::string_view digest, RandomNumberGenerator &rng)
Definition pbes2.cpp:385