Botan 2.19.5 Crypto and TLS for C&

pbes2.cpp
Go to the documentation of this file.
1/*
2* PKCS #5 PBES2
3* (C) 1999-2008,2014 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/pbes2.h>
10#include <botan/cipher_mode.h>
11#include <botan/pbkdf.h>
12#include <botan/pwdhash.h>
13#include <botan/der_enc.h>
14#include <botan/ber_dec.h>
15#include <botan/parsing.h>
16#include <botan/asn1_obj.h>
17#include <botan/oids.h>
18#include <botan/rng.h>
19
20#if defined(BOTAN_HAS_SCRYPT)
21 #include <botan/scrypt.h>
22#endif
23
24 namespace Botan {
25
26 namespace {
27
28 bool known_pbes_cipher_mode(const std::string& mode)
29 {
30 return (mode == "CBC" || mode == "GCM" || mode == "SIV");
31 }
32
33 SymmetricKey derive_key(const std::string& passphrase,
34 const AlgorithmIdentifier& kdf_algo,
35 size_t default_key_size)
36 {
37 if(kdf_algo.get_oid() == OID::from_string("PKCS5.PBKDF2"))
38 {
39 secure_vector<uint8_t> salt;
40 size_t iterations = 0, key_length = 0;
41
42 AlgorithmIdentifier prf_algo;
43 BER_Decoder(kdf_algo.get_parameters())
44 .start_cons(SEQUENCE)
45 .decode(salt, OCTET_STRING)
46 .decode(iterations)
47 .decode_optional(key_length, INTEGER, UNIVERSAL)
48 .decode_optional(prf_algo, SEQUENCE, CONSTRUCTED,
49 AlgorithmIdentifier("HMAC(SHA-160)",
50 AlgorithmIdentifier::USE_NULL_PARAM))
51 .end_cons();
52
53 if(salt.size() < 8)
54 throw Decoding_Error("PBE-PKCS5 v2.0: Encoded salt is too small");
55
56 if(key_length == 0)
57 key_length = default_key_size;
58
59 const std::string prf = OIDS::oid2str_or_throw(prf_algo.get_oid());
60 std::unique_ptr<PBKDF> pbkdf(get_pbkdf("PBKDF2(" + prf + ")"));
61 return pbkdf->pbkdf_iterations(key_length, passphrase, salt.data(), salt.size(), iterations);
62 }
63#if defined(BOTAN_HAS_SCRYPT)
64 else if(kdf_algo.get_oid() == OID::from_string("Scrypt"))
65 {
66 secure_vector<uint8_t> salt;
67 size_t N = 0, r = 0, p = 0;
68 size_t key_length = 0;
69
70 AlgorithmIdentifier prf_algo;
71 BER_Decoder(kdf_algo.get_parameters())
72 .start_cons(SEQUENCE)
73 .decode(salt, OCTET_STRING)
74 .decode(N)
75 .decode(r)
76 .decode(p)
77 .decode_optional(key_length, INTEGER, UNIVERSAL)
78 .end_cons();
79
80 if(key_length == 0)
81 key_length = default_key_size;
82
83 secure_vector<uint8_t> output(key_length);
84 scrypt(output.data(), output.size(), passphrase,
85 salt.data(), salt.size(), N, r, p);
86
87 return SymmetricKey(output);
88 }
89#endif
90 else
91 throw Decoding_Error("PBE-PKCS5 v2.0: Unknown KDF algorithm " +
92 kdf_algo.get_oid().to_string());
93 }
94
95secure_vector<uint8_t> derive_key(const std::string& passphrase,
96 const std::string& digest,
97 RandomNumberGenerator& rng,
98 size_t* msec_in_iterations_out,
99 size_t iterations_if_msec_null,
100 size_t key_length,
101 AlgorithmIdentifier& kdf_algo)
102 {
103 const secure_vector<uint8_t> salt = rng.random_vec(12);
104
105 if(digest == "Scrypt")
106 {
107#if defined(BOTAN_HAS_SCRYPT)
108
109 std::unique_ptr<PasswordHashFamily> pwhash_fam = PasswordHashFamily::create_or_throw("Scrypt");
110
111 std::unique_ptr<PasswordHash> pwhash;
112
113 if(msec_in_iterations_out)
114 {
115 const std::chrono::milliseconds msec(*msec_in_iterations_out);
116 pwhash = pwhash_fam->tune(key_length, msec);
117 }
118 else
119 {
120 pwhash = pwhash_fam->from_iterations(iterations_if_msec_null);
121 }
122
123 secure_vector<uint8_t> key(key_length);
124 pwhash->derive_key(key.data(), key.size(),
125 passphrase.c_str(), passphrase.size(),
126 salt.data(), salt.size());
127
128 const size_t N = pwhash->memory_param();
129 const size_t r = pwhash->iterations();
130 const size_t p = pwhash->parallelism();
131
132 if(msec_in_iterations_out)
133 *msec_in_iterations_out = 0;
134
135 std::vector<uint8_t> scrypt_params;
136 DER_Encoder(scrypt_params)
137 .start_cons(SEQUENCE)
138 .encode(salt, OCTET_STRING)
139 .encode(N)
140 .encode(r)
141 .encode(p)
142 .encode(key_length)
143 .end_cons();
144
145 kdf_algo = AlgorithmIdentifier(OID::from_string("Scrypt"), scrypt_params);
146 return key;
147#else
148 throw Not_Implemented("Scrypt is not available in this build");
149#endif
150 }
151 else
152 {
153 const std::string prf = "HMAC(" + digest + ")";
154 const std::string pbkdf_name = "PBKDF2(" + prf + ")";
155
156 std::unique_ptr<PasswordHashFamily> pwhash_fam = PasswordHashFamily::create(pbkdf_name);
157 if(!pwhash_fam)
158 throw Invalid_Argument("Unknown password hash digest " + digest);
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->derive_key(key.data(), key.size(),
174 passphrase.c_str(), passphrase.size(),
175 salt.data(), salt.size());
176
177 std::vector<uint8_t> pbkdf2_params;
178
179 const size_t iterations = pwhash->iterations();
180
181 if(msec_in_iterations_out)
182 *msec_in_iterations_out = iterations;
183
184 DER_Encoder(pbkdf2_params)
185 .start_cons(SEQUENCE)
186 .encode(salt, OCTET_STRING)
187 .encode(iterations)
188 .encode(key_length)
189 .encode_if(prf != "HMAC(SHA-160)",
190 AlgorithmIdentifier(prf, AlgorithmIdentifier::USE_NULL_PARAM))
191 .end_cons();
192
193 kdf_algo = AlgorithmIdentifier("PKCS5.PBKDF2", pbkdf2_params);
194 return key;
195 }
196 }
197
198/*
199* PKCS#5 v2.0 PBE Encryption
200*/
201std::pair<AlgorithmIdentifier, std::vector<uint8_t>>
202pbes2_encrypt_shared(const secure_vector<uint8_t>& key_bits,
203 const std::string& passphrase,
204 size_t* msec_in_iterations_out,
205 size_t iterations_if_msec_null,
206 const std::string& cipher,
207 const std::string& prf,
208 RandomNumberGenerator& rng)
209 {
210 const std::vector<std::string> cipher_spec = split_on(cipher, '/');
211 if(cipher_spec.size() != 2)
212 throw Encoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher);
213
214 if(!known_pbes_cipher_mode(cipher_spec[1]))
215 throw Encoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher);
216
217 const OID cipher_oid = OIDS::str2oid_or_empty(cipher);
218 if(cipher_oid.empty())
219 throw Encoding_Error("PBE-PKCS5 v2.0: No OID assigned for " + cipher);
220
221 std::unique_ptr<Cipher_Mode> enc = Cipher_Mode::create(cipher, ENCRYPTION);
222
223 if(!enc)
224 throw Decoding_Error("PBE-PKCS5 cannot encrypt no cipher " + cipher);
225
226 const size_t key_length = enc->key_spec().maximum_keylength();
227
228 const secure_vector<uint8_t> iv = rng.random_vec(enc->default_nonce_length());
229
230 AlgorithmIdentifier kdf_algo;
231
232 const secure_vector<uint8_t> derived_key =
233 derive_key(passphrase, prf, rng,
234 msec_in_iterations_out, iterations_if_msec_null,
235 key_length, kdf_algo);
236
237 enc->set_key(derived_key);
238 enc->start(iv);
239 secure_vector<uint8_t> ctext = key_bits;
240 enc->finish(ctext);
241
242 std::vector<uint8_t> encoded_iv;
243 DER_Encoder(encoded_iv).encode(iv, OCTET_STRING);
244
245 std::vector<uint8_t> pbes2_params;
246 DER_Encoder(pbes2_params)
247 .start_cons(SEQUENCE)
248 .encode(kdf_algo)
249 .encode(AlgorithmIdentifier(cipher, encoded_iv))
250 .end_cons();
251
252 AlgorithmIdentifier id(OID::from_string("PBE-PKCS5v20"), pbes2_params);
253
254 return std::make_pair(id, unlock(ctext));
255 }
256
257}
258
259std::pair<AlgorithmIdentifier, std::vector<uint8_t>>
260 pbes2_encrypt(const secure_vector<uint8_t>& key_bits,
261 const std::string& passphrase,
262 std::chrono::milliseconds msec,
263 const std::string& cipher,
264 const std::string& digest,
265 RandomNumberGenerator& rng)
266 {
267 size_t msec_in_iterations_out = static_cast<size_t>(msec.count());
268 return pbes2_encrypt_shared(key_bits, passphrase, &msec_in_iterations_out, 0, cipher, digest, rng);
269 // return value msec_in_iterations_out discarded
270 }
271
272std::pair<AlgorithmIdentifier, std::vector<uint8_t>>
273 pbes2_encrypt_msec(const secure_vector<uint8_t>& key_bits,
274 const std::string& passphrase,
275 std::chrono::milliseconds msec,
276 size_t* out_iterations_if_nonnull,
277 const std::string& cipher,
278 const std::string& digest,
279 RandomNumberGenerator& rng)
280 {
281 size_t msec_in_iterations_out = static_cast<size_t>(msec.count());
282
283 auto ret = pbes2_encrypt_shared(key_bits, passphrase, &msec_in_iterations_out, 0, cipher, digest, rng);
284
285 if(out_iterations_if_nonnull)
286 *out_iterations_if_nonnull = msec_in_iterations_out;
287
288 return ret;
289 }
290
291std::pair<AlgorithmIdentifier, std::vector<uint8_t>>
292 pbes2_encrypt_iter(const secure_vector<uint8_t>& key_bits,
293 const std::string& passphrase,
294 size_t pbkdf_iter,
295 const std::string& cipher,
296 const std::string& digest,
297 RandomNumberGenerator& rng)
298 {
299 return pbes2_encrypt_shared(key_bits, passphrase, nullptr, pbkdf_iter, cipher, digest, rng);
300 }
301
302secure_vector<uint8_t>
303 pbes2_decrypt(const secure_vector<uint8_t>& key_bits,
304 const std::string& passphrase,
305 const std::vector<uint8_t>& params)
306 {
307 AlgorithmIdentifier kdf_algo, enc_algo;
308
309 BER_Decoder(params)
310 .start_cons(SEQUENCE)
311 .decode(kdf_algo)
312 .decode(enc_algo)
313 .end_cons();
314
315 const std::string cipher = OIDS::oid2str_or_throw(enc_algo.get_oid());
316 const std::vector<std::string> cipher_spec = split_on(cipher, '/');
317 if(cipher_spec.size() != 2)
318 throw Decoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher);
319 if(!known_pbes_cipher_mode(cipher_spec[1]))
320 throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher);
321
322 secure_vector<uint8_t> iv;
323 BER_Decoder(enc_algo.get_parameters()).decode(iv, OCTET_STRING).verify_end();
324
325 std::unique_ptr<Cipher_Mode> dec = Cipher_Mode::create(cipher, DECRYPTION);
326 if(!dec)
327 throw Decoding_Error("PBE-PKCS5 cannot decrypt no cipher " + cipher);
328
329 dec->set_key(derive_key(passphrase, kdf_algo, dec->key_spec().maximum_keylength()));
330
331 dec->start(iv);
332
333 secure_vector<uint8_t> buf = key_bits;
334 dec->finish(buf);
335
336 return buf;
337 }
338
339}
Botan::AlgorithmIdentifier
Definition: asn1_obj.h:430
Botan::AlgorithmIdentifier::USE_NULL_PARAM
@ USE_NULL_PARAM
Definition: asn1_obj.h:432
Botan::AlgorithmIdentifier::get_parameters
const std::vector< uint8_t > & get_parameters() const
Definition: asn1_obj.h:446
Botan::AlgorithmIdentifier::get_oid
const OID & get_oid() const
Definition: asn1_obj.h:445
Botan::BER_Decoder
Definition: ber_dec.h:22
Botan::BER_Decoder::start_cons
BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: ber_dec.cpp:290
Botan::BER_Decoder::decode
BER_Decoder & decode(bool &out)
Definition: ber_dec.h:170
Botan::BER_Decoder::verify_end
BER_Decoder & verify_end()
Definition: ber_dec.cpp:208
Botan::BER_Decoder::end_cons
BER_Decoder & end_cons()
Definition: ber_dec.cpp:300
Botan::Cipher_Mode::create
static std::unique_ptr< Cipher_Mode > create(const std::string &algo, Cipher_Dir direction, const std::string &provider="")
Definition: cipher_mode.cpp:50
Botan::Decoding_Error
Definition: exceptn.h:200
Botan::OID::from_string
static OID from_string(const std::string &str)
Definition: asn1_oid.cpp:62
Botan::PasswordHashFamily::create_or_throw
static std::unique_ptr< PasswordHashFamily > create_or_throw(const std::string &algo_spec, const std::string &provider="")
Definition: pwdhash.cpp:101
Botan::PasswordHashFamily::create
static std::unique_ptr< PasswordHashFamily > create(const std::string &algo_spec, const std::string &provider="")
Definition: pwdhash.cpp:33
Botan::RandomNumberGenerator
Definition: rng.h:26
Botan::OIDS::oid2str_or_throw
BOTAN_UNSTABLE_API std::string oid2str_or_throw(const OID &oid)
Definition: oids.cpp:121
Botan::OIDS::str2oid_or_empty
BOTAN_UNSTABLE_API OID str2oid_or_empty(const std::string &name)
Definition: oids.cpp:116
Botan
Definition: alg_id.cpp:13
Botan::split_on
std::vector< std::string > split_on(const std::string &str, char delim)
Definition: parsing.cpp:148
Botan::pbes2_encrypt_msec
std::pair< AlgorithmIdentifier, std::vector< uint8_t > > pbes2_encrypt_msec(const secure_vector< uint8_t > &key_bits, const std::string &passphrase, std::chrono::milliseconds msec, size_t *out_iterations_if_nonnull, const std::string &cipher, const std::string &digest, RandomNumberGenerator &rng)
Definition: pbes2.cpp:273
Botan::get_pbkdf
PBKDF * get_pbkdf(const std::string &algo_spec, const std::string &provider="")
Definition: pbkdf.h:232
Botan::scrypt
void scrypt(uint8_t output[], size_t output_len, const char *password, size_t password_len, const uint8_t salt[], size_t salt_len, size_t N, size_t r, size_t p)
Definition: scrypt.cpp:211
Botan::unlock
std::vector< T > unlock(const secure_vector< T > &in)
Definition: secmem.h:72
Botan::SymmetricKey
OctetString SymmetricKey
Definition: symkey.h:141
Botan::DECRYPTION
@ DECRYPTION
Definition: cipher_mode.h:23
Botan::ENCRYPTION
@ ENCRYPTION
Definition: cipher_mode.h:23
Botan::pbes2_encrypt_iter
std::pair< AlgorithmIdentifier, std::vector< uint8_t > > pbes2_encrypt_iter(const secure_vector< uint8_t > &key_bits, const std::string &passphrase, size_t pbkdf_iter, const std::string &cipher, const std::string &digest, RandomNumberGenerator &rng)
Definition: pbes2.cpp:292
Botan::CONSTRUCTED
@ CONSTRUCTED
Definition: asn1_obj.h:30
Botan::SEQUENCE
@ SEQUENCE
Definition: asn1_obj.h:42
Botan::OCTET_STRING
@ OCTET_STRING
Definition: asn1_obj.h:38
Botan::UNIVERSAL
@ UNIVERSAL
Definition: asn1_obj.h:26
Botan::INTEGER
@ INTEGER
Definition: asn1_obj.h:36
Botan::secure_vector
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:65
Botan::pbes2_encrypt
std::pair< AlgorithmIdentifier, std::vector< uint8_t > > pbes2_encrypt(const secure_vector< uint8_t > &key_bits, const std::string &passphrase, std::chrono::milliseconds msec, const std::string &cipher, const std::string &digest, RandomNumberGenerator &rng)
Definition: pbes2.cpp:260
Botan::pbes2_decrypt
secure_vector< uint8_t > pbes2_decrypt(const secure_vector< uint8_t > &key_bits, const std::string &passphrase, const std::vector< uint8_t > &params)
Definition: pbes2.cpp:303