9#include <botan/internal/pbes2.h>
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>
17#include <botan/internal/fmt.h>
18#include <botan/internal/parsing.h>
24bool known_pbes_cipher_mode(std::string_view mode) {
25 return (mode ==
"CBC" || mode ==
"GCM" || mode ==
"SIV");
30 size_t default_key_size) {
33 size_t iterations = 0;
34 size_t key_length = 0;
53 key_length = default_key_size;
56 const std::string prf = prf_algo.oid().human_name_or_empty();
57 if(prf.empty() || !prf.starts_with(
"HMAC")) {
62 auto pbkdf = pbkdf_fam->from_params(iterations);
65 pbkdf->hash(derived_key, passphrase, salt);
72 size_t key_length = 0;
85 key_length = default_key_size;
91 auto pwdhash = pwdhash_fam->from_params(N, r, p);
92 pwdhash->hash(derived_key, passphrase, salt);
96 throw Decoding_Error(
fmt(
"PBE-PKCS5 v2.0: Unknown KDF algorithm {}", kdf_algo.oid()));
101 std::string_view digest,
103 size_t* msec_in_iterations_out,
104 size_t iterations_if_msec_null,
106 bool include_key_length_in_struct,
108 const size_t salt_len = 16;
111 if(digest ==
"Scrypt") {
114 std::unique_ptr<PasswordHash> pwhash;
116 if(msec_in_iterations_out !=
nullptr) {
117 const std::chrono::milliseconds msec(*msec_in_iterations_out);
118 pwhash = pwhash_fam->tune(key_length, msec);
120 pwhash = pwhash_fam->from_iterations(iterations_if_msec_null);
124 pwhash->hash(key, passphrase, salt);
126 const size_t N = pwhash->memory_param();
127 const size_t r = pwhash->iterations();
128 const size_t p = pwhash->parallelism();
130 if(msec_in_iterations_out !=
nullptr) {
131 *msec_in_iterations_out = 0;
134 std::vector<uint8_t> scrypt_params;
141 .
encode_if(include_key_length_in_struct, key_length)
147 const std::string prf =
fmt(
"HMAC({})", digest);
148 const std::string pbkdf_name =
fmt(
"PBKDF2({})", prf);
155 std::unique_ptr<PasswordHash> pwhash;
157 if(msec_in_iterations_out !=
nullptr) {
158 const std::chrono::milliseconds msec(*msec_in_iterations_out);
159 pwhash = pwhash_fam->tune(key_length, msec);
161 pwhash = pwhash_fam->from_iterations(iterations_if_msec_null);
165 pwhash->hash(key, passphrase, salt);
167 std::vector<uint8_t> pbkdf2_params;
169 const size_t iterations = pwhash->iterations();
171 if(msec_in_iterations_out !=
nullptr) {
172 *msec_in_iterations_out = iterations;
179 .
encode_if(include_key_length_in_struct, key_length)
191std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbes2_encrypt_shared(std::span<const uint8_t> key_bits,
192 std::string_view passphrase,
193 size_t* msec_in_iterations_out,
194 size_t iterations_if_msec_null,
195 std::string_view cipher,
196 std::string_view prf,
200 const auto cipher_spec =
split_on(cipher,
'/');
202 if(cipher_spec.size() != 2 || !known_pbes_cipher_mode(cipher_spec[1]) || !enc) {
203 throw Encoding_Error(
fmt(
"PBE-PKCS5 v2.0: Invalid or unavailable cipher '{}'", cipher));
206 const size_t key_length =
enc->key_spec().maximum_keylength();
212 const bool include_key_length_in_struct =
enc->key_spec().minimum_keylength() !=
enc->key_spec().maximum_keylength();
214 const auto derived_key = derive_key(passphrase,
217 msec_in_iterations_out,
218 iterations_if_msec_null,
220 include_key_length_in_struct,
223 enc->set_key(derived_key);
228 std::vector<uint8_t> encoded_iv;
231 std::vector<uint8_t> pbes2_params;
240 return std::make_pair(
id,
unlock(ctext));
245std::pair<AlgorithmIdentifier, std::vector<uint8_t>>
pbes2_encrypt(std::span<const uint8_t> key_bits,
246 std::string_view passphrase,
247 std::chrono::milliseconds msec,
248 std::string_view cipher,
249 std::string_view digest,
251 size_t msec_in_iterations_out =
static_cast<size_t>(msec.count());
252 return pbes2_encrypt_shared(key_bits, passphrase, &msec_in_iterations_out, 0, cipher, digest, rng);
256std::pair<AlgorithmIdentifier, std::vector<uint8_t>>
pbes2_encrypt_msec(std::span<const uint8_t> key_bits,
257 std::string_view passphrase,
258 std::chrono::milliseconds msec,
259 size_t* out_iterations_if_nonnull,
260 std::string_view cipher,
261 std::string_view digest,
263 size_t msec_in_iterations_out =
static_cast<size_t>(msec.count());
265 auto ret = pbes2_encrypt_shared(key_bits, passphrase, &msec_in_iterations_out, 0, cipher, digest, rng);
267 if(out_iterations_if_nonnull !=
nullptr) {
268 *out_iterations_if_nonnull = msec_in_iterations_out;
274std::pair<AlgorithmIdentifier, std::vector<uint8_t>>
pbes2_encrypt_iter(std::span<const uint8_t> key_bits,
275 std::string_view passphrase,
277 std::string_view cipher,
278 std::string_view digest,
280 return pbes2_encrypt_shared(key_bits, passphrase,
nullptr, pbkdf_iter, cipher, digest, rng);
284 std::string_view passphrase,
285 const std::vector<uint8_t>& params) {
292 const auto cipher_spec =
split_on(cipher,
'/');
293 if(cipher_spec.size() != 2 || !known_pbes_cipher_mode(cipher_spec[1])) {
305 dec->set_key(derive_key(passphrase, kdf_algo, dec->key_spec().maximum_keylength()));
const std::vector< uint8_t > & parameters() const
BER_Decoder & decode(bool &out)
BER_Decoder & verify_end()
BER_Decoder start_sequence()
BER_Decoder & decode_optional(T &out, ASN1_Type type_tag, ASN1_Class class_tag, const T &default_value=T())
static std::unique_ptr< Cipher_Mode > create(std::string_view algo, Cipher_Dir direction, std::string_view provider="")
DER_Encoder & start_sequence()
DER_Encoder & encode_if(bool pred, DER_Encoder &enc)
DER_Encoder & encode(bool b)
std::string human_name_or_empty() const
static OID from_string(std::string_view str)
static std::unique_ptr< PasswordHashFamily > create_or_throw(std::string_view algo_spec, std::string_view provider="")
static std::unique_ptr< PasswordHashFamily > create(std::string_view algo_spec, std::string_view provider="")
BOTAN_FORCE_INLINE BOTAN_FN_ISA_AES void enc(uint8x16_t &B, uint8x16_t K)
std::string fmt(std::string_view format, const T &... args)
std::vector< std::string > split_on(std::string_view str, char delim)
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)
secure_vector< uint8_t > pbes2_decrypt(std::span< const uint8_t > key_bits, std::string_view passphrase, const std::vector< uint8_t > ¶ms)
std::vector< T > unlock(const secure_vector< T > &in)
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)
std::vector< T, secure_allocator< T > > secure_vector
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)