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/internal/scan_name.h>
16#include <botan/pk_algs.h>
18#if defined(BOTAN_HAS_PKCS5_PBES2)
19 #include <botan/internal/pbes2.h>
48 const std::function<std::string ()>& get_passphrase,
60 key_data = PKCS8_extract(source, pbe_alg_id);
71 key_data.push_back(
b);
82 if(label ==
"PRIVATE KEY")
84 else if(label ==
"ENCRYPTED PRIVATE KEY")
87 key_data = PKCS8_extract(key_source, pbe_alg_id);
107#if defined(BOTAN_HAS_PKCS5_PBES2)
111 throw Decoding_Error(
"Private key is encrypted but PBES2 was disabled in build");
125 catch(std::exception& e)
142#if defined(BOTAN_HAS_PKCS5_PBES2)
146std::pair<std::string, std::string>
147choose_pbe_params(
const std::string& pbe_algo,
const std::string& key_algo)
156 const bool nonstandard_pk = (key_algo ==
"McEliece" || key_algo ==
"XMSS");
160#if defined(BOTAN_HAS_AEAD_SIV) && defined(BOTAN_HAS_SHA2_64)
161 return std::make_pair(
"AES-256/SIV",
"SHA-512");
162#elif defined(BOTAN_HAS_AEAD_GCM) && defined(BOTAN_HAS_SHA2_64)
163 return std::make_pair(
"AES-256/GCM",
"SHA-512");
168 return std::make_pair(
"AES-256/CBC",
"SHA-256");
171 SCAN_Name request(pbe_algo);
173 if(request.arg_count() != 2 ||
174 (request.algo_name() !=
"PBE-PKCS5v20" && request.algo_name() !=
"PBES2"))
176 throw Invalid_Argument(
"Unsupported PBE " + pbe_algo);
179 return std::make_pair(request.arg(0), request.arg(1));
191 const std::string& pass,
192 std::chrono::milliseconds msec,
193 const std::string& pbe_algo)
195#if defined(BOTAN_HAS_PKCS5_PBES2)
196 const auto pbe_params = choose_pbe_params(pbe_algo, key.
algo_name());
198 const std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbe_info =
200 pbe_params.first, pbe_params.second, rng);
202 std::vector<uint8_t> output;
212 throw Encoding_Error(
"PKCS8::BER_encode cannot encrypt because PBES2 was disabled in build");
221 const std::string& pass,
222 std::chrono::milliseconds msec,
223 const std::string& pbe_algo)
229 "ENCRYPTED PRIVATE KEY");
237 const std::string& pass,
238 size_t pbkdf_iterations,
239 const std::string& cipher,
240 const std::string& pbkdf_hash)
242#if defined(BOTAN_HAS_PKCS5_PBES2)
243 const std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbe_info =
245 pass, pbkdf_iterations,
246 cipher.empty() ?
"AES-256/CBC" : cipher,
247 pbkdf_hash.empty() ?
"SHA-256" : pbkdf_hash,
250 std::vector<uint8_t> output;
260 BOTAN_UNUSED(key, rng, pass, pbkdf_iterations, cipher, pbkdf_hash);
261 throw Encoding_Error(
"PKCS8::BER_encode_encrypted_pbkdf_iter cannot encrypt because PBES2 disabled in build");
270 const std::string& pass,
271 size_t pbkdf_iterations,
272 const std::string& cipher,
273 const std::string& pbkdf_hash)
277 "ENCRYPTED PRIVATE KEY");
285 const std::string& pass,
286 std::chrono::milliseconds pbkdf_msec,
287 size_t* pbkdf_iterations,
288 const std::string& cipher,
289 const std::string& pbkdf_hash)
291#if defined(BOTAN_HAS_PKCS5_PBES2)
292 const std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbe_info =
294 pbkdf_msec, pbkdf_iterations,
295 cipher.empty() ?
"AES-256/CBC" : cipher,
296 pbkdf_hash.empty() ?
"SHA-256" : pbkdf_hash,
299 std::vector<uint8_t> output;
308 BOTAN_UNUSED(key, rng, pass, pbkdf_msec, pbkdf_iterations, cipher, pbkdf_hash);
309 throw Encoding_Error(
"BER_encode_encrypted_pbkdf_msec cannot encrypt because PBES2 disabled in build");
318 const std::string& pass,
319 std::chrono::milliseconds pbkdf_msec,
320 size_t* pbkdf_iterations,
321 const std::string& cipher,
322 const std::string& pbkdf_hash)
326 "ENCRYPTED PRIVATE KEY");
334std::unique_ptr<Private_Key>
336 const std::function<std::string ()>& get_pass,
356 const std::function<std::string ()>& get_pass)
358 return load_key(source, get_pass,
true);
365 const std::string& pass)
369 return load_key(source, std::bind([](
const std::string& p) {
return p; }, pass),
true);
377 auto fail_fn = []() -> std::string {
378 throw PKCS8_Exception(
"Internal error: Attempt to read password for unencrypted key");
381 return load_key(source, fail_fn,
false);
#define BOTAN_UNUSED(...)
const std::vector< uint8_t > & get_parameters() const
const OID & get_oid() const
BER_Decoder & decode(bool &out)
BER_Decoder & decode_and_check(const T &expected, const std::string &error_msg)
BER_Decoder & verify_end()
BER_Decoder start_sequence()
DER_Encoder & start_sequence()
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::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::vector< uint8_t > BER_encode(const Private_Key &key, RandomNumberGenerator &rng, const std::string &pass, std::chrono::milliseconds msec, const std::string &pbe_algo)
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::unique_ptr< Private_Key > load_key(DataSource &source, const std::function< std::string()> &get_pass)
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)