8#include <botan/pkcs8.h>
10#include <botan/asn1_obj.h>
11#include <botan/assert.h>
12#include <botan/ber_dec.h>
13#include <botan/der_enc.h>
15#include <botan/pk_algs.h>
17#include <botan/internal/fmt.h>
18#include <botan/internal/scan_name.h>
20#if defined(BOTAN_HAS_PKCS5_PBES2)
21 #include <botan/internal/pbes2.h>
43 const std::function<std::string()>& get_passphrase,
52 key_data = PKCS8_extract(source, pbe_alg_id);
59 key_data.push_back(b);
68 if(label ==
"PRIVATE KEY") {
70 }
else if(label ==
"ENCRYPTED PRIVATE KEY") {
72 key_data = PKCS8_extract(key_source, pbe_alg_id);
78 if(key_data.empty()) {
91#if defined(BOTAN_HAS_PKCS5_PBES2)
95 throw Decoding_Error(
"Private key is encrypted but PBES2 was disabled in build");
108 }
catch(std::exception& e) {
123#if defined(BOTAN_HAS_PKCS5_PBES2)
127std::pair<std::string, std::string> choose_pbe_params(std::string_view pbe_algo, std::string_view key_algo) {
128 if(pbe_algo.empty()) {
134 const bool nonstandard_pk = (key_algo ==
"McEliece" || key_algo ==
"XMSS");
137 #if defined(BOTAN_HAS_AEAD_SIV) && defined(BOTAN_HAS_SHA2_64)
138 return std::make_pair(
"AES-256/SIV",
"SHA-512");
139 #elif defined(BOTAN_HAS_AEAD_GCM) && defined(BOTAN_HAS_SHA2_64)
140 return std::make_pair(
"AES-256/GCM",
"SHA-512");
145 return std::make_pair(
"AES-256/CBC",
"SHA-256");
148 SCAN_Name request(pbe_algo);
150 if(request.arg_count() != 2 || (request.algo_name() !=
"PBE-PKCS5v20" && request.algo_name() !=
"PBES2")) {
151 throw Invalid_Argument(
fmt(
"Unsupported PBE '{}'", pbe_algo));
154 return std::make_pair(request.arg(0), request.arg(1));
166 std::string_view pass,
167 std::chrono::milliseconds msec,
168 std::string_view pbe_algo) {
169#if defined(BOTAN_HAS_PKCS5_PBES2)
170 const auto pbe_params = choose_pbe_params(pbe_algo, key.
algo_name());
172 const std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbe_info =
175 std::vector<uint8_t> output;
182 throw Encoding_Error(
"PKCS8::BER_encode cannot encrypt because PBES2 was disabled in build");
191 std::string_view pass,
192 std::chrono::milliseconds msec,
193 std::string_view pbe_algo) {
206 std::string_view pass,
207 size_t pbkdf_iterations,
208 std::string_view cipher,
209 std::string_view pbkdf_hash) {
210#if defined(BOTAN_HAS_PKCS5_PBES2)
211 const std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbe_info =
215 cipher.empty() ?
"AES-256/CBC" : cipher,
216 pbkdf_hash.empty() ?
"SHA-256" : pbkdf_hash,
219 std::vector<uint8_t> output;
226 BOTAN_UNUSED(key, rng, pass, pbkdf_iterations, cipher, pbkdf_hash);
227 throw Encoding_Error(
"PKCS8::BER_encode_encrypted_pbkdf_iter cannot encrypt because PBES2 disabled in build");
236 std::string_view pass,
237 size_t pbkdf_iterations,
238 std::string_view cipher,
239 std::string_view pbkdf_hash) {
241 "ENCRYPTED PRIVATE KEY");
249 std::string_view pass,
250 std::chrono::milliseconds pbkdf_msec,
251 size_t* pbkdf_iterations,
252 std::string_view cipher,
253 std::string_view pbkdf_hash) {
254#if defined(BOTAN_HAS_PKCS5_PBES2)
255 const std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbe_info =
260 cipher.empty() ?
"AES-256/CBC" : cipher,
261 pbkdf_hash.empty() ?
"SHA-256" : pbkdf_hash,
264 std::vector<uint8_t> output;
273 BOTAN_UNUSED(key, rng, pass, pbkdf_msec, pbkdf_iterations, cipher, pbkdf_hash);
274 throw Encoding_Error(
"BER_encode_encrypted_pbkdf_msec cannot encrypt because PBES2 disabled in build");
283 std::string_view pass,
284 std::chrono::milliseconds pbkdf_msec,
285 size_t* pbkdf_iterations,
286 std::string_view cipher,
287 std::string_view pbkdf_hash) {
290 "ENCRYPTED PRIVATE KEY");
299 const std::function<std::string()>& get_pass,
305 if(alg_name.empty()) {
317std::unique_ptr<Private_Key>
load_key(
DataSource& source,
const std::function<std::string()>& get_pass) {
318 return load_key(source, get_pass,
true);
321std::unique_ptr<Private_Key>
load_key(std::span<const uint8_t> source,
322 const std::function<std::string()>& get_passphrase) {
324 return load_key(ds, get_passphrase);
327std::unique_ptr<Private_Key>
load_key(std::span<const uint8_t> source, std::string_view pass) {
332std::unique_ptr<Private_Key>
load_key(std::span<const uint8_t> source) {
342 source, [pass]() {
return std::string(pass); },
true);
349 auto fail_fn = []() -> std::string {
350 throw PKCS8_Exception(
"Internal error: Attempt to read password for unencrypted key");
353 return load_key(source, fail_fn,
false);
const std::vector< uint8_t > & parameters() const
virtual std::string algo_name() const =0
BER_Decoder & decode(bool &out)
BER_Decoder & verify_end()
BER_Decoder start_sequence()
BER_Decoder & decode_and_check(const T &expected, std::string_view error_msg)
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_formatted_string() const
std::string human_name_or_empty() const
secure_vector< uint8_t > private_key_info() const
bool maybe_BER(DataSource &source)
std::string encode(const uint8_t der[], size_t length, std::string_view label, size_t width)
bool matches(DataSource &source, std::string_view extra, size_t search_range)
secure_vector< uint8_t > decode(DataSource &source, std::string &label)
std::vector< uint8_t > BER_encode(const Private_Key &key, RandomNumberGenerator &rng, std::string_view pass, std::chrono::milliseconds msec, std::string_view pbe_algo)
std::string PEM_encode_encrypted_pbkdf_iter(const Private_Key &key, RandomNumberGenerator &rng, std::string_view pass, size_t pbkdf_iterations, std::string_view cipher, std::string_view pbkdf_hash)
std::string PEM_encode(const Private_Key &key)
std::string PEM_encode_encrypted_pbkdf_msec(const Private_Key &key, RandomNumberGenerator &rng, std::string_view pass, std::chrono::milliseconds pbkdf_msec, size_t *pbkdf_iterations, std::string_view cipher, std::string_view pbkdf_hash)
std::vector< uint8_t > BER_encode_encrypted_pbkdf_iter(const Private_Key &key, RandomNumberGenerator &rng, std::string_view pass, size_t pbkdf_iterations, std::string_view cipher, std::string_view pbkdf_hash)
std::vector< uint8_t > BER_encode_encrypted_pbkdf_msec(const Private_Key &key, RandomNumberGenerator &rng, std::string_view pass, std::chrono::milliseconds pbkdf_msec, size_t *pbkdf_iterations, std::string_view cipher, std::string_view pbkdf_hash)
std::unique_ptr< Private_Key > load_key(DataSource &source, const std::function< std::string()> &get_pass)
std::string fmt(std::string_view format, const T &... args)
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::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::unique_ptr< Private_Key > load_private_key(const AlgorithmIdentifier &alg_id, std::span< const uint8_t > key_bits)