8#include <botan/pkcs8.h>
10#include <botan/der_enc.h>
11#include <botan/ber_dec.h>
12#include <botan/asn1_obj.h>
13#include <botan/oids.h>
15#include <botan/scan_name.h>
16#include <botan/pk_algs.h>
18#if defined(BOTAN_HAS_PKCS5_PBES2)
19 #include <botan/pbes2.h>
50 std::function<std::string ()> get_passphrase,
62 key_data = PKCS8_extract(source, pbe_alg_id);
73 key_data.push_back(b);
84 if(label ==
"PRIVATE KEY")
86 else if(label ==
"ENCRYPTED PRIVATE KEY")
89 key_data = PKCS8_extract(key_source, pbe_alg_id);
109#if defined(BOTAN_HAS_PKCS5_PBES2)
113 throw Decoding_Error(
"Private key is encrypted but PBES2 was disabled in build");
127 catch(std::exception& e)
153#if defined(BOTAN_HAS_PKCS5_PBES2)
157std::pair<std::string, std::string>
158choose_pbe_params(
const std::string& pbe_algo,
const std::string& key_algo)
167 const bool nonstandard_pk = (key_algo ==
"McEliece" || key_algo ==
"XMSS");
171#if defined(BOTAN_HAS_AEAD_SIV) && defined(BOTAN_HAS_SHA2_64)
172 return std::make_pair(
"AES-256/SIV",
"SHA-512");
173#elif defined(BOTAN_HAS_AEAD_GCM) && defined(BOTAN_HAS_SHA2_64)
174 return std::make_pair(
"AES-256/GCM",
"SHA-512");
179 return std::make_pair(
"AES-256/CBC",
"SHA-256");
182 SCAN_Name request(pbe_algo);
184 if(request.arg_count() != 2 ||
185 (request.algo_name() !=
"PBE-PKCS5v20" && request.algo_name() !=
"PBES2"))
187 throw Invalid_Argument(
"Unsupported PBE " + pbe_algo);
190 return std::make_pair(request.arg(0), request.arg(1));
202 const std::string& pass,
203 std::chrono::milliseconds msec,
204 const std::string& pbe_algo)
206#if defined(BOTAN_HAS_PKCS5_PBES2)
207 const auto pbe_params = choose_pbe_params(pbe_algo, key.
algo_name());
209 const std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbe_info =
211 pbe_params.first, pbe_params.second, rng);
213 std::vector<uint8_t> output;
223 throw Encoding_Error(
"PKCS8::BER_encode cannot encrypt because PBES2 was disabled in build");
232 const std::string& pass,
233 std::chrono::milliseconds msec,
234 const std::string& pbe_algo)
240 "ENCRYPTED PRIVATE KEY");
248 const std::string& pass,
249 size_t pbkdf_iterations,
250 const std::string& cipher,
251 const std::string& pbkdf_hash)
253#if defined(BOTAN_HAS_PKCS5_PBES2)
254 const std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbe_info =
256 pass, pbkdf_iterations,
257 cipher.empty() ?
"AES-256/CBC" : cipher,
258 pbkdf_hash.empty() ?
"SHA-256" : pbkdf_hash,
261 std::vector<uint8_t> output;
271 BOTAN_UNUSED(key, rng, pass, pbkdf_iterations, cipher, pbkdf_hash);
272 throw Encoding_Error(
"PKCS8::BER_encode_encrypted_pbkdf_iter cannot encrypt because PBES2 disabled in build");
281 const std::string& pass,
282 size_t pbkdf_iterations,
283 const std::string& cipher,
284 const std::string& pbkdf_hash)
288 "ENCRYPTED PRIVATE KEY");
296 const std::string& pass,
297 std::chrono::milliseconds pbkdf_msec,
298 size_t* pbkdf_iterations,
299 const std::string& cipher,
300 const std::string& pbkdf_hash)
302#if defined(BOTAN_HAS_PKCS5_PBES2)
303 const std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbe_info =
305 pbkdf_msec, pbkdf_iterations,
306 cipher.empty() ?
"AES-256/CBC" : cipher,
307 pbkdf_hash.empty() ?
"SHA-256" : pbkdf_hash,
310 std::vector<uint8_t> output;
319 BOTAN_UNUSED(key, rng, pass, pbkdf_msec, pbkdf_iterations, cipher, pbkdf_hash);
320 throw Encoding_Error(
"BER_encode_encrypted_pbkdf_msec cannot encrypt because PBES2 disabled in build");
329 const std::string& pass,
330 std::chrono::milliseconds pbkdf_msec,
331 size_t* pbkdf_iterations,
332 const std::string& cipher,
333 const std::string& pbkdf_hash)
337 "ENCRYPTED PRIVATE KEY");
345std::unique_ptr<Private_Key>
347 std::function<std::string ()> get_pass,
367 std::function<std::string ()> get_pass)
369 return load_key(source, get_pass,
true);
376 const std::string& pass)
380 return load_key(source, std::bind([](
const std::string p) {
return p; }, pass),
true);
388 auto fail_fn = []() -> std::string {
389 throw PKCS8_Exception(
"Internal error: Attempt to read password for unencrypted key");
392 return load_key(source, fail_fn,
false);
409 std::function<std::string ()> get_pass)
420 const std::string& pass)
436#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
443 std::function<std::string ()> get_pass)
453Private_Key*
load_key(
const std::string& fsname,
454 RandomNumberGenerator& rng,
455 const std::string& pass)
458 DataSource_Stream in(fsname);
461 return PKCS8::load_key(in, std::bind([](
const std::string p) {
return p; }, pass)).release();
467Private_Key*
load_key(
const std::string& fsname,
468 RandomNumberGenerator& rng)
471 DataSource_Stream in(fsname);
#define BOTAN_UNUSED(...)
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 & decode_and_check(const T &expected, const std::string &error_msg)
BER_Decoder & verify_end()
DER_Encoder & start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
DER_Encoder & encode(bool b)
size_t read_byte(uint8_t &out)
virtual bool end_of_data() const =0
std::string to_string() const
secure_vector< uint8_t > private_key_info() const
virtual std::string algo_name() const =0
bool maybe_BER(DataSource &source)
BOTAN_UNSTABLE_API std::string oid2str_or_throw(const OID &oid)
BOTAN_UNSTABLE_API std::string oid2str_or_empty(const OID &oid)
std::string encode(const uint8_t der[], size_t length, const std::string &label, size_t width)
bool matches(DataSource &source, const std::string &extra, size_t search_range)
secure_vector< uint8_t > decode(DataSource &source, std::string &label)
std::unique_ptr< Private_Key > copy_key(const Private_Key &key)
std::vector< uint8_t > BER_encode_encrypted_pbkdf_iter(const Private_Key &key, RandomNumberGenerator &rng, const std::string &pass, size_t pbkdf_iterations, const std::string &cipher, const std::string &pbkdf_hash)
std::string PEM_encode(const Private_Key &key)
std::string PEM_encode_encrypted_pbkdf_msec(const Private_Key &key, RandomNumberGenerator &rng, const std::string &pass, std::chrono::milliseconds pbkdf_msec, size_t *pbkdf_iterations, const std::string &cipher, const std::string &pbkdf_hash)
std::unique_ptr< Private_Key > load_key(DataSource &source, std::function< std::string()> get_pass)
secure_vector< uint8_t > BER_encode(const Private_Key &key)
std::vector< uint8_t > BER_encode_encrypted_pbkdf_msec(const Private_Key &key, RandomNumberGenerator &rng, const std::string &pass, std::chrono::milliseconds pbkdf_msec, size_t *pbkdf_iterations, const std::string &cipher, const std::string &pbkdf_hash)
std::string PEM_encode_encrypted_pbkdf_iter(const Private_Key &key, RandomNumberGenerator &rng, const std::string &pass, size_t pbkdf_iterations, const std::string &cipher, const std::string &pbkdf_hash)
std::unique_ptr< Private_Key > load_private_key(const AlgorithmIdentifier &alg_id, const secure_vector< uint8_t > &key_bits)
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)
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
secure_vector< uint8_t > pbes2_decrypt(const secure_vector< uint8_t > &key_bits, const std::string &passphrase, const std::vector< uint8_t > ¶ms)