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>
20#if defined(BOTAN_HAS_SCRYPT)
21 #include <botan/scrypt.h>
28bool known_pbes_cipher_mode(
const std::string& mode)
30 return (mode ==
"CBC" || mode ==
"GCM" || mode ==
"SIV");
34 const AlgorithmIdentifier& kdf_algo,
35 size_t default_key_size)
39 secure_vector<uint8_t> salt;
40 size_t iterations = 0, key_length = 0;
42 AlgorithmIdentifier prf_algo;
43 BER_Decoder(kdf_algo.get_parameters())
49 AlgorithmIdentifier(
"HMAC(SHA-160)",
54 throw Decoding_Error(
"PBE-PKCS5 v2.0: Encoded salt is too small");
57 key_length = default_key_size;
60 std::unique_ptr<PBKDF> pbkdf(
get_pbkdf(
"PBKDF2(" + prf +
")"));
61 return pbkdf->pbkdf_iterations(key_length, passphrase, salt.data(), salt.size(), iterations);
63#if defined(BOTAN_HAS_SCRYPT)
66 secure_vector<uint8_t> salt;
67 size_t N = 0, r = 0, p = 0;
68 size_t key_length = 0;
70 AlgorithmIdentifier prf_algo;
71 BER_Decoder(kdf_algo.get_parameters())
81 key_length = default_key_size;
83 secure_vector<uint8_t> output(key_length);
84 scrypt(output.data(), output.size(), passphrase,
85 salt.data(), salt.size(), N, r, p);
91 throw Decoding_Error(
"PBE-PKCS5 v2.0: Unknown KDF algorithm " +
92 kdf_algo.get_oid().to_string());
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,
101 AlgorithmIdentifier& kdf_algo)
103 const secure_vector<uint8_t> salt = rng.random_vec(12);
105 if(digest ==
"Scrypt")
107#if defined(BOTAN_HAS_SCRYPT)
111 std::unique_ptr<PasswordHash> pwhash;
113 if(msec_in_iterations_out)
115 const std::chrono::milliseconds msec(*msec_in_iterations_out);
116 pwhash = pwhash_fam->tune(key_length, msec);
120 pwhash = pwhash_fam->from_iterations(iterations_if_msec_null);
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());
128 const size_t N = pwhash->memory_param();
129 const size_t r = pwhash->iterations();
130 const size_t p = pwhash->parallelism();
132 if(msec_in_iterations_out)
133 *msec_in_iterations_out = 0;
135 std::vector<uint8_t> scrypt_params;
136 DER_Encoder(scrypt_params)
148 throw Not_Implemented(
"Scrypt is not available in this build");
153 const std::string prf =
"HMAC(" + digest +
")";
154 const std::string pbkdf_name =
"PBKDF2(" + prf +
")";
158 throw Invalid_Argument(
"Unknown password hash digest " + digest);
160 std::unique_ptr<PasswordHash> pwhash;
162 if(msec_in_iterations_out)
164 const std::chrono::milliseconds msec(*msec_in_iterations_out);
165 pwhash = pwhash_fam->tune(key_length, msec);
169 pwhash = pwhash_fam->from_iterations(iterations_if_msec_null);
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());
177 std::vector<uint8_t> pbkdf2_params;
179 const size_t iterations = pwhash->iterations();
181 if(msec_in_iterations_out)
182 *msec_in_iterations_out = iterations;
184 DER_Encoder(pbkdf2_params)
189 .encode_if(prf !=
"HMAC(SHA-160)",
193 kdf_algo = AlgorithmIdentifier(
"PKCS5.PBKDF2", pbkdf2_params);
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)
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);
214 if(!known_pbes_cipher_mode(cipher_spec[1]))
215 throw Encoding_Error(
"PBE-PKCS5 v2.0: Don't know param format for " + cipher);
218 if(cipher_oid.empty())
219 throw Encoding_Error(
"PBE-PKCS5 v2.0: No OID assigned for " + cipher);
224 throw Decoding_Error(
"PBE-PKCS5 cannot encrypt no cipher " + cipher);
226 const size_t key_length = enc->key_spec().maximum_keylength();
228 const secure_vector<uint8_t> iv = rng.random_vec(enc->default_nonce_length());
230 AlgorithmIdentifier kdf_algo;
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);
237 enc->set_key(derived_key);
239 secure_vector<uint8_t> ctext = key_bits;
242 std::vector<uint8_t> encoded_iv;
245 std::vector<uint8_t> pbes2_params;
246 DER_Encoder(pbes2_params)
249 .encode(AlgorithmIdentifier(cipher, encoded_iv))
254 return std::make_pair(
id,
unlock(ctext));
259std::pair<AlgorithmIdentifier, std::vector<uint8_t>>
261 const std::string& passphrase,
262 std::chrono::milliseconds msec,
263 const std::string& cipher,
264 const std::string& digest,
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);
272std::pair<AlgorithmIdentifier, std::vector<uint8_t>>
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,
281 size_t msec_in_iterations_out =
static_cast<size_t>(msec.count());
283 auto ret = pbes2_encrypt_shared(key_bits, passphrase, &msec_in_iterations_out, 0, cipher, digest, rng);
285 if(out_iterations_if_nonnull)
286 *out_iterations_if_nonnull = msec_in_iterations_out;
291std::pair<AlgorithmIdentifier, std::vector<uint8_t>>
293 const std::string& passphrase,
295 const std::string& cipher,
296 const std::string& digest,
299 return pbes2_encrypt_shared(key_bits, passphrase,
nullptr, pbkdf_iter, cipher, digest, rng);
302secure_vector<uint8_t>
304 const std::string& passphrase,
305 const std::vector<uint8_t>& params)
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);
327 throw Decoding_Error(
"PBE-PKCS5 cannot decrypt no cipher " + cipher);
329 dec->set_key(derive_key(passphrase, kdf_algo, dec->key_spec().maximum_keylength()));
const std::vector< uint8_t > & get_parameters() const
const OID & get_oid() const
BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
BER_Decoder & decode(bool &out)
BER_Decoder & verify_end()
static std::unique_ptr< Cipher_Mode > create(const std::string &algo, Cipher_Dir direction, const std::string &provider="")
static OID from_string(const std::string &str)
static std::unique_ptr< PasswordHashFamily > create_or_throw(const std::string &algo_spec, const std::string &provider="")
static std::unique_ptr< PasswordHashFamily > create(const std::string &algo_spec, const std::string &provider="")
BOTAN_UNSTABLE_API std::string oid2str_or_throw(const OID &oid)
BOTAN_UNSTABLE_API OID str2oid_or_empty(const std::string &name)
std::vector< std::string > split_on(const std::string &str, char delim)
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)
PBKDF * get_pbkdf(const std::string &algo_spec, const std::string &provider="")
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)
std::vector< T > unlock(const secure_vector< T > &in)
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)
std::vector< T, secure_allocator< T > > secure_vector
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)
secure_vector< uint8_t > pbes2_decrypt(const secure_vector< uint8_t > &key_bits, const std::string &passphrase, const std::vector< uint8_t > ¶ms)