8#include <botan/internal/pkcs12_pbe.h>
10#include <botan/asn1_obj.h>
11#include <botan/ber_dec.h>
12#include <botan/cipher_mode.h>
13#include <botan/der_enc.h>
14#include <botan/exceptn.h>
16#include <botan/internal/fmt.h>
17#include <botan/internal/pkcs12_kdf.h>
21#include <botan/internal/pbes2.h>
28struct PKCS12_PBE_Params {
30 std::string cipher_name;
34PKCS12_PBE_Params pkcs12_pbe_params_for_oid(
const OID& oid) {
36 return {oid,
"TripleDES/CBC", 24};
39 return {oid,
"TripleDES/CBC", 16};
41 throw Decoding_Error(
fmt(
"Unsupported PKCS#12 PBE algorithm: {}", oid.to_string()));
44PKCS12_PBE_Params pkcs12_pbe_params_for_algo(std::string_view algo) {
45 if(algo ==
"PBE-SHA1-3DES") {
48 if(algo ==
"PBE-SHA1-2DES") {
60 const std::vector<uint8_t>& salt,
62 const PKCS12_PBE_Params& params,
63 bool openssl_empty_pwd_compat) {
64 constexpr size_t iv_len = 8;
69 const bool ossl_empty = openssl_empty_pwd_compat && password.empty();
73 pkcs12_kdf({key.data(), params.key_len}, {}, {salt.data(), salt.size()}, iterations, 1, *hash);
74 pkcs12_kdf({iv.data(), iv_len}, {}, {salt.data(), salt.size()}, iterations, 2, *hash);
76 const PKCS12_KDF kdf_key(hash->new_object(), 1, iterations);
77 kdf_key.derive_key(key.data(), params.key_len, password.data(), password.size(), salt.data(), salt.size());
79 const PKCS12_KDF kdf_iv(hash->new_object(), 2, iterations);
80 kdf_iv.derive_key(iv.data(), iv_len, password.data(), password.size(), salt.data(), salt.size());
83 if(params.key_len == 16) {
85 std::copy(key.begin(), key.begin() + 8, key.begin() + 16);
87 return {std::move(key), std::move(iv)};
93 std::string_view password,
95 bool openssl_empty_pwd_compat) {
96 const OID& oid = pbe_algo.
oid();
104 std::vector<uint8_t> salt;
105 size_t iterations = 0;
114 throw Decoding_Error(
fmt(
"PKCS#12 PBE has invalid iteration count: {}", iterations));
117 const auto params = pkcs12_pbe_params_for_oid(oid);
118 auto [key, iv] = pkcs12_derive_key_iv(password, salt, iterations, params, openssl_empty_pwd_compat);
121 cipher->set_key(key);
125 cipher->finish(plaintext);
130std::pair<AlgorithmIdentifier, std::vector<uint8_t>>
pkcs12_pbe_encrypt(std::span<const uint8_t> plaintext,
131 std::string_view password,
132 std::string_view algo,
139 if(algo ==
"PBES2-SHA256-AES256") {
140 auto [aid, ct] =
pbes2_encrypt_iter(plaintext, password, iterations,
"AES-256/CBC",
"SHA-256", rng);
141 return {std::move(aid), std::move(ct)};
143 if(algo ==
"PBES2-SHA256-AES128") {
144 auto [aid, ct] =
pbes2_encrypt_iter(plaintext, password, iterations,
"AES-128/CBC",
"SHA-256", rng);
145 return {std::move(aid), std::move(ct)};
148 const auto params = pkcs12_pbe_params_for_algo(algo);
150 std::vector<uint8_t> salt(8);
153 auto [key, iv] = pkcs12_derive_key_iv(password, salt, iterations, params,
false);
156 cipher->set_key(key);
159 std::vector<uint8_t> ciphertext(plaintext.begin(), plaintext.end());
160 cipher->finish(ciphertext);
162 std::vector<uint8_t> enc_params;
const std::vector< uint8_t > & parameters() const
BER_Decoder & decode(bool &out)
BER_Decoder & verify_end()
BER_Decoder start_sequence()
static std::unique_ptr< Cipher_Mode > create_or_throw(std::string_view algo, Cipher_Dir direction, std::string_view provider="")
DER_Encoder & start_sequence()
DER_Encoder & encode(bool b)
static std::unique_ptr< HashFunction > create_or_throw(std::string_view algo_spec, std::string_view provider="")
static OID from_string(std::string_view str)
void randomize(std::span< uint8_t > output)
std::string fmt(std::string_view format, const T &... args)
secure_vector< uint8_t > pkcs12_pbe_decrypt(std::span< const uint8_t > ciphertext, std::string_view password, const AlgorithmIdentifier &pbe_algo, bool openssl_empty_pwd_compat)
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, secure_allocator< T > > secure_vector
std::pair< AlgorithmIdentifier, std::vector< uint8_t > > pkcs12_pbe_encrypt(std::span< const uint8_t > plaintext, std::string_view password, std::string_view algo, size_t iterations, RandomNumberGenerator &rng)
void pkcs12_kdf(std::span< uint8_t > out, std::span< const uint8_t > pwd_bytes, std::span< const uint8_t > salt, size_t iterations, uint8_t id, HashFunction &hash)
constexpr size_t PKCS12_MAX_ITERATIONS