Botan 3.0.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#include <botan/cipher_mode.h>
11#include <botan/pwdhash.h>
12#include <botan/der_enc.h>
13#include <botan/ber_dec.h>
14#include <botan/internal/parsing.h>
15#include <botan/internal/fmt.h>
16#include <botan/asn1_obj.h>
17#include <botan/rng.h>
18
19namespace Botan {
20
21namespace {
22
23bool known_pbes_cipher_mode(std::string_view mode)
24 {
25 return (mode == "CBC" || mode == "GCM" || mode == "SIV");
26 }
27
28secure_vector<uint8_t> derive_key(std::string_view passphrase,
29 const AlgorithmIdentifier& kdf_algo,
30 size_t default_key_size)
31 {
32 if(kdf_algo.oid() == OID::from_string("PKCS5.PBKDF2"))
33 {
34 secure_vector<uint8_t> salt;
35 size_t iterations = 0, key_length = 0;
36
37 AlgorithmIdentifier prf_algo;
38 BER_Decoder(kdf_algo.parameters())
39 .start_sequence()
40 .decode(salt, ASN1_Type::OctetString)
41 .decode(iterations)
42 .decode_optional(key_length, ASN1_Type::Integer, ASN1_Class::Universal)
43 .decode_optional(prf_algo, ASN1_Type::Sequence, ASN1_Class::Constructed,
44 AlgorithmIdentifier("HMAC(SHA-1)",
46 .end_cons();
47
48 if(salt.size() < 8)
49 throw Decoding_Error("PBE-PKCS5 v2.0: Encoded salt is too small");
50
51 if(key_length == 0)
52 key_length = default_key_size;
53
54 const std::string prf = prf_algo.oid().human_name_or_empty();
55 if(prf.empty() || !prf.starts_with("HMAC"))
56 {
57 throw Decoding_Error(fmt("Unknown PBES2 PRF {}", prf_algo.oid()));
58 }
59
60 auto pbkdf_fam = PasswordHashFamily::create_or_throw(fmt("PBKDF2({})", prf));
61 auto pbkdf = pbkdf_fam->from_params(iterations);
62
63 secure_vector<uint8_t> derived_key(key_length);
64 pbkdf->hash(derived_key, passphrase, salt);
65 return derived_key;
66 }
67 else if(kdf_algo.oid() == OID::from_string("Scrypt"))
68 {
69 secure_vector<uint8_t> salt;
70 size_t N = 0, r = 0, p = 0;
71 size_t key_length = 0;
72
73 AlgorithmIdentifier prf_algo;
74 BER_Decoder(kdf_algo.parameters())
75 .start_sequence()
76 .decode(salt, ASN1_Type::OctetString)
77 .decode(N)
78 .decode(r)
79 .decode(p)
80 .decode_optional(key_length, ASN1_Type::Integer, ASN1_Class::Universal)
81 .end_cons();
82
83 if(key_length == 0)
84 key_length = default_key_size;
85
86 secure_vector<uint8_t> derived_key(key_length);
87
88 auto pwdhash_fam = PasswordHashFamily::create_or_throw("Scrypt");
89 auto pwdhash = pwdhash_fam->from_params(N, r, p);
90 pwdhash->hash(derived_key, passphrase, salt);
91
92 return derived_key;
93 }
94 else
95 {
96 throw Decoding_Error(fmt("PBE-PKCS5 v2.0: Unknown KDF algorithm {}", kdf_algo.oid()));
97 }
98 }
99
100secure_vector<uint8_t> derive_key(std::string_view passphrase,
101 std::string_view digest,
102 RandomNumberGenerator& rng,
103 size_t* msec_in_iterations_out,
104 size_t iterations_if_msec_null,
105 size_t key_length,
106 AlgorithmIdentifier& kdf_algo)
107 {
108 const secure_vector<uint8_t> salt = rng.random_vec(12);
109
110 if(digest == "Scrypt")
111 {
112 auto pwhash_fam = PasswordHashFamily::create_or_throw("Scrypt");
113
114 std::unique_ptr<PasswordHash> pwhash;
115
116 if(msec_in_iterations_out)
117 {
118 const std::chrono::milliseconds msec(*msec_in_iterations_out);
119 pwhash = pwhash_fam->tune(key_length, msec);
120 }
121 else
122 {
123 pwhash = pwhash_fam->from_iterations(iterations_if_msec_null);
124 }
125
126 secure_vector<uint8_t> key(key_length);
127 pwhash->hash(key, passphrase, salt);
128
129 const size_t N = pwhash->memory_param();
130 const size_t r = pwhash->iterations();
131 const size_t p = pwhash->parallelism();
132
133 if(msec_in_iterations_out)
134 *msec_in_iterations_out = 0;
135
136 std::vector<uint8_t> scrypt_params;
137 DER_Encoder(scrypt_params)
138 .start_sequence()
139 .encode(salt, ASN1_Type::OctetString)
140 .encode(N)
141 .encode(r)
142 .encode(p)
143 .encode(key_length)
144 .end_cons();
145
146 kdf_algo = AlgorithmIdentifier(OID::from_string("Scrypt"), scrypt_params);
147 return key;
148 }
149 else
150 {
151 const std::string prf = fmt("HMAC({})", digest);
152 const std::string pbkdf_name = fmt("PBKDF2({})", prf);
153
154 auto pwhash_fam = PasswordHashFamily::create(pbkdf_name);
155 if(!pwhash_fam)
156 {
157 throw Invalid_Argument(fmt("Unknown password hash digest {}", digest));
158 }
159
160 std::unique_ptr<PasswordHash> pwhash;
161
162 if(msec_in_iterations_out)
163 {
164 const std::chrono::milliseconds msec(*msec_in_iterations_out);
165 pwhash = pwhash_fam->tune(key_length, msec);
166 }
167 else
168 {
169 pwhash = pwhash_fam->from_iterations(iterations_if_msec_null);
170 }
171
172 secure_vector<uint8_t> key(key_length);
173 pwhash->hash(key, passphrase, salt);
174
175 std::vector<uint8_t> pbkdf2_params;
176
177 const size_t iterations = pwhash->iterations();
178
179 if(msec_in_iterations_out)
180 *msec_in_iterations_out = iterations;
181
182 DER_Encoder(pbkdf2_params)
183 .start_sequence()
184 .encode(salt, ASN1_Type::OctetString)
185 .encode(iterations)
186 .encode(key_length)
187 .encode_if(prf != "HMAC(SHA-1)",
188 AlgorithmIdentifier(prf, AlgorithmIdentifier::USE_NULL_PARAM))
189 .end_cons();
190
191 kdf_algo = AlgorithmIdentifier("PKCS5.PBKDF2", pbkdf2_params);
192 return key;
193 }
194 }
195
196/*
197* PKCS#5 v2.0 PBE Encryption
198*/
199std::pair<AlgorithmIdentifier, std::vector<uint8_t>>
200pbes2_encrypt_shared(std::span<const uint8_t> key_bits,
201 std::string_view passphrase,
202 size_t* msec_in_iterations_out,
203 size_t iterations_if_msec_null,
204 std::string_view cipher,
205 std::string_view prf,
206 RandomNumberGenerator& rng)
207 {
209
210 const auto cipher_spec = split_on(cipher, '/');
211
212 if(cipher_spec.size() != 2 || !known_pbes_cipher_mode(cipher_spec[1]) || !enc)
213 {
214 throw Encoding_Error(fmt("PBE-PKCS5 v2.0: Invalid or unavailable cipher '{}'", cipher));
215 }
216
217 const size_t key_length = enc->key_spec().maximum_keylength();
218
219 const secure_vector<uint8_t> iv = rng.random_vec(enc->default_nonce_length());
220
221 AlgorithmIdentifier kdf_algo;
222
223 const secure_vector<uint8_t> derived_key =
224 derive_key(passphrase, prf, rng,
225 msec_in_iterations_out, iterations_if_msec_null,
226 key_length, kdf_algo);
227
228 enc->set_key(derived_key);
229 enc->start(iv);
230 secure_vector<uint8_t> ctext(key_bits.begin(), key_bits.end());
231 enc->finish(ctext);
232
233 std::vector<uint8_t> encoded_iv;
234 DER_Encoder(encoded_iv).encode(iv, ASN1_Type::OctetString);
235
236 std::vector<uint8_t> pbes2_params;
237 DER_Encoder(pbes2_params)
238 .start_sequence()
239 .encode(kdf_algo)
240 .encode(AlgorithmIdentifier(cipher, encoded_iv))
241 .end_cons();
242
243 AlgorithmIdentifier id(OID::from_string("PBE-PKCS5v20"), pbes2_params);
244
245 return std::make_pair(id, unlock(ctext));
246 }
247
248}
249
250std::pair<AlgorithmIdentifier, std::vector<uint8_t>>
251pbes2_encrypt(std::span<const uint8_t> key_bits,
252 std::string_view passphrase,
253 std::chrono::milliseconds msec,
254 std::string_view cipher,
255 std::string_view digest,
257 {
258 size_t msec_in_iterations_out = static_cast<size_t>(msec.count());
259 return pbes2_encrypt_shared(key_bits, passphrase, &msec_in_iterations_out, 0, cipher, digest, rng);
260 // return value msec_in_iterations_out discarded
261 }
262
263std::pair<AlgorithmIdentifier, std::vector<uint8_t>>
264pbes2_encrypt_msec(std::span<const uint8_t> key_bits,
265 std::string_view passphrase,
266 std::chrono::milliseconds msec,
267 size_t* out_iterations_if_nonnull,
268 std::string_view cipher,
269 std::string_view digest,
271 {
272 size_t msec_in_iterations_out = static_cast<size_t>(msec.count());
273
274 auto ret = pbes2_encrypt_shared(key_bits, passphrase, &msec_in_iterations_out, 0, cipher, digest, rng);
275
276 if(out_iterations_if_nonnull)
277 *out_iterations_if_nonnull = msec_in_iterations_out;
278
279 return ret;
280 }
281
282std::pair<AlgorithmIdentifier, std::vector<uint8_t>>
283pbes2_encrypt_iter(std::span<const uint8_t> key_bits,
284 std::string_view passphrase,
285 size_t pbkdf_iter,
286 std::string_view cipher,
287 std::string_view digest,
289 {
290 return pbes2_encrypt_shared(key_bits, passphrase, nullptr, pbkdf_iter, cipher, digest, rng);
291 }
292
293secure_vector<uint8_t>
294pbes2_decrypt(std::span<const uint8_t> key_bits,
295 std::string_view passphrase,
296 const std::vector<uint8_t>& params)
297 {
298 AlgorithmIdentifier kdf_algo, enc_algo;
299
300 BER_Decoder(params)
302 .decode(kdf_algo)
303 .decode(enc_algo)
304 .end_cons();
305
306 const std::string cipher = enc_algo.oid().human_name_or_empty();
307 const auto cipher_spec = split_on(cipher, '/');
308 if(cipher_spec.size() != 2 || !known_pbes_cipher_mode(cipher_spec[1]))
309 {
310 throw Decoding_Error(fmt("PBE-PKCS5 v2.0: Unknown/invalid cipher OID {}", enc_algo.oid()));
311 }
312
315
317 if(!dec)
318 {
319 throw Decoding_Error(fmt("PBE-PKCS5 cannot decrypt no cipher '{}'", cipher));
320 }
321
322 dec->set_key(derive_key(passphrase, kdf_algo, dec->key_spec().maximum_keylength()));
323
324 dec->start(iv);
325
326 secure_vector<uint8_t> buf(key_bits.begin(), key_bits.end());
327 dec->finish(buf);
328
329 return buf;
330 }
331
332}
const std::vector< uint8_t > & parameters() const
Definition: asn1_obj.h:478
const OID & oid() const
Definition: asn1_obj.h:477
BER_Decoder & decode(bool &out)
Definition: ber_dec.h:193
BER_Decoder & verify_end()
Definition: ber_dec.cpp:211
BER_Decoder & end_cons()
Definition: ber_dec.cpp:304
BER_Decoder start_sequence()
Definition: ber_dec.h:117
static std::unique_ptr< Cipher_Mode > create(std::string_view algo, Cipher_Dir direction, std::string_view provider="")
Definition: cipher_mode.cpp:50
std::string human_name_or_empty() const
Definition: asn1_oid.cpp:128
static OID from_string(std::string_view str)
Definition: asn1_oid.cpp:78
static std::unique_ptr< PasswordHashFamily > create_or_throw(std::string_view algo_spec, std::string_view provider="")
Definition: pwdhash.cpp:118
static std::unique_ptr< PasswordHashFamily > create(std::string_view algo_spec, std::string_view provider="")
Definition: pwdhash.cpp:50
Definition: alg_id.cpp:12
std::string fmt(std::string_view format, const T &... args)
Definition: fmt.h:60
std::vector< std::string > split_on(std::string_view str, char delim)
Definition: parsing.cpp:117
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:283
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:294
std::vector< T > unlock(const secure_vector< T > &in)
Definition: secmem.h:77
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:264
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:64
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:251