aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/pbe
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/pbe')
-rw-r--r--src/lib/pbe/get_pbe.cpp140
-rw-r--r--src/lib/pbe/get_pbe.h44
-rw-r--r--src/lib/pbe/info.txt7
-rw-r--r--src/lib/pbe/pbe.h39
-rw-r--r--src/lib/pbe/pbes1/info.txt10
-rw-r--r--src/lib/pbe/pbes1/pbes1.cpp193
-rw-r--r--src/lib/pbe/pbes1/pbes1.h69
-rw-r--r--src/lib/pbe/pbes2/info.txt14
-rw-r--r--src/lib/pbe/pbes2/pbes2.cpp209
-rw-r--r--src/lib/pbe/pbes2/pbes2.h70
10 files changed, 795 insertions, 0 deletions
diff --git a/src/lib/pbe/get_pbe.cpp b/src/lib/pbe/get_pbe.cpp
new file mode 100644
index 000000000..4ec518776
--- /dev/null
+++ b/src/lib/pbe/get_pbe.cpp
@@ -0,0 +1,140 @@
+/*
+* PBE Retrieval
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/get_pbe.h>
+#include <botan/oids.h>
+#include <botan/scan_name.h>
+#include <botan/parsing.h>
+#include <botan/libstate.h>
+
+#if defined(BOTAN_HAS_PBE_PKCS_V15)
+ #include <botan/pbes1.h>
+#endif
+
+#if defined(BOTAN_HAS_PBE_PKCS_V20)
+ #include <botan/pbes2.h>
+ #include <botan/hmac.h>
+#endif
+
+namespace Botan {
+
+/*
+* Get an encryption PBE, set new parameters
+*/
+PBE* get_pbe(const std::string& algo_spec,
+ const std::string& passphrase,
+ std::chrono::milliseconds msec,
+ RandomNumberGenerator& rng)
+ {
+ SCAN_Name request(algo_spec);
+
+ const std::string pbe = request.algo_name();
+ std::string digest_name = request.arg(0);
+ const std::string cipher = request.arg(1);
+
+ std::vector<std::string> cipher_spec = split_on(cipher, '/');
+ if(cipher_spec.size() != 2)
+ throw Invalid_Argument("PBE: Invalid cipher spec " + cipher);
+
+ const std::string cipher_algo = SCAN_Name::deref_alias(cipher_spec[0]);
+ const std::string cipher_mode = cipher_spec[1];
+
+ if(cipher_mode != "CBC")
+ throw Invalid_Argument("PBE: Invalid cipher mode " + cipher);
+
+ Algorithm_Factory& af = global_state().algorithm_factory();
+
+ const BlockCipher* block_cipher = af.prototype_block_cipher(cipher_algo);
+ if(!block_cipher)
+ throw Algorithm_Not_Found(cipher_algo);
+
+ const HashFunction* hash_function = af.prototype_hash_function(digest_name);
+ if(!hash_function)
+ throw Algorithm_Not_Found(digest_name);
+
+ if(request.arg_count() != 2)
+ throw Invalid_Algorithm_Name(algo_spec);
+
+#if defined(BOTAN_HAS_PBE_PKCS_V15)
+ if(pbe == "PBE-PKCS5v15")
+ return new PBE_PKCS5v15(block_cipher->clone(),
+ hash_function->clone(),
+ passphrase,
+ msec,
+ rng);
+#endif
+
+#if defined(BOTAN_HAS_PBE_PKCS_V20)
+ if(pbe == "PBE-PKCS5v20")
+ return new PBE_PKCS5v20(block_cipher->clone(),
+ new HMAC(hash_function->clone()),
+ passphrase,
+ msec,
+ rng);
+#endif
+
+ throw Algorithm_Not_Found(algo_spec);
+ }
+
+/*
+* Get a decryption PBE, decode parameters
+*/
+PBE* get_pbe(const OID& pbe_oid,
+ const std::vector<byte>& params,
+ const std::string& passphrase)
+ {
+ SCAN_Name request(OIDS::lookup(pbe_oid));
+
+ const std::string pbe = request.algo_name();
+
+#if defined(BOTAN_HAS_PBE_PKCS_V15)
+ if(pbe == "PBE-PKCS5v15")
+ {
+ if(request.arg_count() != 2)
+ throw Invalid_Algorithm_Name(request.as_string());
+
+ std::string digest_name = request.arg(0);
+ const std::string cipher = request.arg(1);
+
+ std::vector<std::string> cipher_spec = split_on(cipher, '/');
+ if(cipher_spec.size() != 2)
+ throw Invalid_Argument("PBE: Invalid cipher spec " + cipher);
+
+ const std::string cipher_algo = SCAN_Name::deref_alias(cipher_spec[0]);
+ const std::string cipher_mode = cipher_spec[1];
+
+ if(cipher_mode != "CBC")
+ throw Invalid_Argument("PBE: Invalid cipher mode " + cipher);
+
+ Algorithm_Factory& af = global_state().algorithm_factory();
+
+ const BlockCipher* block_cipher = af.prototype_block_cipher(cipher_algo);
+ if(!block_cipher)
+ throw Algorithm_Not_Found(cipher_algo);
+
+ const HashFunction* hash_function =
+ af.prototype_hash_function(digest_name);
+
+ if(!hash_function)
+ throw Algorithm_Not_Found(digest_name);
+
+ return new PBE_PKCS5v15(block_cipher->clone(),
+ hash_function->clone(),
+ params,
+ passphrase);
+ }
+#endif
+
+#if defined(BOTAN_HAS_PBE_PKCS_V20)
+ if(pbe == "PBE-PKCS5v20")
+ return new PBE_PKCS5v20(params, passphrase);
+#endif
+
+ throw Algorithm_Not_Found(pbe_oid.as_string());
+ }
+
+}
diff --git a/src/lib/pbe/get_pbe.h b/src/lib/pbe/get_pbe.h
new file mode 100644
index 000000000..df87c0547
--- /dev/null
+++ b/src/lib/pbe/get_pbe.h
@@ -0,0 +1,44 @@
+/*
+* PBE Lookup
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_LOOKUP_PBE_H__
+#define BOTAN_LOOKUP_PBE_H__
+
+#include <botan/pbe.h>
+#include <vector>
+#include <string>
+#include <chrono>
+
+namespace Botan {
+
+/**
+* Factory function for PBEs.
+* @param algo_spec the name of the PBE algorithm to retrieve
+* @param passphrase the passphrase to use for encryption
+* @param msec how many milliseconds to run the PBKDF
+* @param rng a random number generator
+* @return pointer to a PBE with randomly created parameters
+*/
+BOTAN_DLL PBE* get_pbe(const std::string& algo_spec,
+ const std::string& passphrase,
+ std::chrono::milliseconds msec,
+ RandomNumberGenerator& rng);
+
+/**
+* Factory function for PBEs.
+* @param pbe_oid the oid of the desired PBE
+* @param params a DataSource providing the DER encoded parameters to use
+* @param passphrase the passphrase to use for decryption
+* @return pointer to the PBE with the specified parameters
+*/
+BOTAN_DLL PBE* get_pbe(const OID& pbe_oid,
+ const std::vector<byte>& params,
+ const std::string& passphrase);
+
+}
+
+#endif
diff --git a/src/lib/pbe/info.txt b/src/lib/pbe/info.txt
new file mode 100644
index 000000000..0436c4efd
--- /dev/null
+++ b/src/lib/pbe/info.txt
@@ -0,0 +1,7 @@
+define PASSWORD_BASED_ENCRYPTION 20131128
+
+<requires>
+filters
+libstate
+oid_lookup
+</requires>
diff --git a/src/lib/pbe/pbe.h b/src/lib/pbe/pbe.h
new file mode 100644
index 000000000..45c98e2c8
--- /dev/null
+++ b/src/lib/pbe/pbe.h
@@ -0,0 +1,39 @@
+/*
+* PBE
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_PBE_BASE_H__
+#define BOTAN_PBE_BASE_H__
+
+#include <botan/asn1_oid.h>
+#include <botan/data_src.h>
+#include <botan/filter.h>
+#include <botan/rng.h>
+
+namespace Botan {
+
+/**
+* Password Based Encryption (PBE) Filter.
+*/
+class BOTAN_DLL PBE : public Filter
+ {
+ public:
+ /**
+ * DER encode the params (the number of iterations and the salt value)
+ * @return encoded params
+ */
+ virtual std::vector<byte> encode_params() const = 0;
+
+ /**
+ * Get this PBE's OID.
+ * @return object identifier
+ */
+ virtual OID get_oid() const = 0;
+ };
+
+}
+
+#endif
diff --git a/src/lib/pbe/pbes1/info.txt b/src/lib/pbe/pbes1/info.txt
new file mode 100644
index 000000000..36d26ecc9
--- /dev/null
+++ b/src/lib/pbe/pbes1/info.txt
@@ -0,0 +1,10 @@
+define PBE_PKCS_V15 20131128
+
+<requires>
+asn1
+block
+cbc
+filters
+hash
+pbkdf1
+</requires>
diff --git a/src/lib/pbe/pbes1/pbes1.cpp b/src/lib/pbe/pbes1/pbes1.cpp
new file mode 100644
index 000000000..a30f10a6c
--- /dev/null
+++ b/src/lib/pbe/pbes1/pbes1.cpp
@@ -0,0 +1,193 @@
+/*
+* PKCS #5 PBES1
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/pbes1.h>
+#include <botan/pbkdf1.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/lookup.h>
+#include <algorithm>
+
+namespace Botan {
+
+/*
+* Encrypt some bytes using PBES1
+*/
+void PBE_PKCS5v15::write(const byte input[], size_t length)
+ {
+ m_pipe.write(input, length);
+ flush_pipe(true);
+ }
+
+/*
+* Start encrypting with PBES1
+*/
+void PBE_PKCS5v15::start_msg()
+ {
+ m_pipe.append(get_cipher(m_block_cipher->name() + "/CBC/PKCS7",
+ m_key, m_iv, m_direction));
+
+ m_pipe.start_msg();
+ if(m_pipe.message_count() > 1)
+ m_pipe.set_default_msg(m_pipe.default_msg() + 1);
+ }
+
+/*
+* Finish encrypting with PBES1
+*/
+void PBE_PKCS5v15::end_msg()
+ {
+ m_pipe.end_msg();
+ flush_pipe(false);
+ m_pipe.reset();
+ }
+
+/*
+* Flush the pipe
+*/
+void PBE_PKCS5v15::flush_pipe(bool safe_to_skip)
+ {
+ if(safe_to_skip && m_pipe.remaining() < 64)
+ return;
+
+ secure_vector<byte> buffer(DEFAULT_BUFFERSIZE);
+ while(m_pipe.remaining())
+ {
+ size_t got = m_pipe.read(&buffer[0], buffer.size());
+ send(buffer, got);
+ }
+ }
+
+/*
+* Encode PKCS#5 PBES1 parameters
+*/
+std::vector<byte> PBE_PKCS5v15::encode_params() const
+ {
+ return DER_Encoder()
+ .start_cons(SEQUENCE)
+ .encode(m_salt, OCTET_STRING)
+ .encode(m_iterations)
+ .end_cons()
+ .get_contents_unlocked();
+ }
+
+/*
+* Return an OID for this PBES1 type
+*/
+OID PBE_PKCS5v15::get_oid() const
+ {
+ const OID base_pbes1_oid("1.2.840.113549.1.5");
+
+ const std::string cipher = m_block_cipher->name();
+ const std::string digest = m_hash_function->name();
+
+ if(cipher == "DES" && digest == "MD2")
+ return (base_pbes1_oid + 1);
+ else if(cipher == "DES" && digest == "MD5")
+ return (base_pbes1_oid + 3);
+ else if(cipher == "DES" && digest == "SHA-160")
+ return (base_pbes1_oid + 10);
+ else if(cipher == "RC2" && digest == "MD2")
+ return (base_pbes1_oid + 4);
+ else if(cipher == "RC2" && digest == "MD5")
+ return (base_pbes1_oid + 6);
+ else if(cipher == "RC2" && digest == "SHA-160")
+ return (base_pbes1_oid + 11);
+ else
+ throw Internal_Error("PBE-PKCS5 v1.5: get_oid() has run out of options");
+ }
+
+std::string PBE_PKCS5v15::name() const
+ {
+ return "PBE-PKCS5v15(" + m_block_cipher->name() + "," +
+ m_hash_function->name() + ")";
+ }
+
+PBE_PKCS5v15::PBE_PKCS5v15(BlockCipher* cipher,
+ HashFunction* hash,
+ const std::string& passphrase,
+ std::chrono::milliseconds msec,
+ RandomNumberGenerator& rng) :
+ m_direction(ENCRYPTION),
+ m_block_cipher(cipher),
+ m_hash_function(hash),
+ m_salt(rng.random_vec(8))
+ {
+ if(cipher->name() != "DES" && cipher->name() != "RC2")
+ {
+ throw Invalid_Argument("PBE_PKCS5v1.5: Unknown cipher " +
+ cipher->name());
+ }
+
+ if(hash->name() != "MD2" && hash->name() != "MD5" &&
+ hash->name() != "SHA-160")
+ {
+ throw Invalid_Argument("PBE_PKCS5v1.5: Unknown hash " +
+ hash->name());
+ }
+
+ PKCS5_PBKDF1 pbkdf(m_hash_function->clone());
+
+ secure_vector<byte> key_and_iv =
+ pbkdf.derive_key(16, passphrase,
+ &m_salt[0], m_salt.size(),
+ msec, m_iterations).bits_of();
+
+ m_key.assign(&key_and_iv[0], &key_and_iv[8]);
+ m_iv.assign(&key_and_iv[8], &key_and_iv[16]);
+
+ }
+
+PBE_PKCS5v15::PBE_PKCS5v15(BlockCipher* cipher,
+ HashFunction* hash,
+ const std::vector<byte>& params,
+ const std::string& passphrase) :
+ m_direction(DECRYPTION),
+ m_block_cipher(cipher),
+ m_hash_function(hash)
+ {
+ if(cipher->name() != "DES" && cipher->name() != "RC2")
+ {
+ throw Invalid_Argument("PBE_PKCS5v1.5: Unknown cipher " +
+ cipher->name());
+ }
+
+ if(hash->name() != "MD2" && hash->name() != "MD5" &&
+ hash->name() != "SHA-160")
+ {
+ throw Invalid_Argument("PBE_PKCS5v1.5: Unknown hash " +
+ hash->name());
+ }
+
+ BER_Decoder(params)
+ .start_cons(SEQUENCE)
+ .decode(m_salt, OCTET_STRING)
+ .decode(m_iterations)
+ .verify_end()
+ .end_cons();
+
+ if(m_salt.size() != 8)
+ throw Decoding_Error("PBES1: Encoded salt is not 8 octets");
+
+ PKCS5_PBKDF1 pbkdf(m_hash_function->clone());
+
+ secure_vector<byte> key_and_iv =
+ pbkdf.derive_key(16, passphrase,
+ &m_salt[0], m_salt.size(),
+ m_iterations).bits_of();
+
+ m_key.assign(&key_and_iv[0], &key_and_iv[8]);
+ m_iv.assign(&key_and_iv[8], &key_and_iv[16]);
+ }
+
+PBE_PKCS5v15::~PBE_PKCS5v15()
+ {
+ delete m_block_cipher;
+ delete m_hash_function;
+ }
+
+}
diff --git a/src/lib/pbe/pbes1/pbes1.h b/src/lib/pbe/pbes1/pbes1.h
new file mode 100644
index 000000000..8d1a6f877
--- /dev/null
+++ b/src/lib/pbe/pbes1/pbes1.h
@@ -0,0 +1,69 @@
+/*
+* PKCS #5 v1.5 PBE
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_PBE_PKCS_V15_H__
+#define BOTAN_PBE_PKCS_V15_H__
+
+#include <botan/pbe.h>
+#include <botan/block_cipher.h>
+#include <botan/hash.h>
+#include <botan/pipe.h>
+#include <chrono>
+
+namespace Botan {
+
+/**
+* PKCS #5 v1.5 PBE
+*/
+class BOTAN_DLL PBE_PKCS5v15 : public PBE
+ {
+ public:
+ OID get_oid() const;
+
+ std::vector<byte> encode_params() const;
+
+ std::string name() const;
+
+ void write(const byte[], size_t);
+ void start_msg();
+ void end_msg();
+
+ /**
+ * @param cipher the block cipher to use (DES or RC2)
+ * @param hash the hash function to use
+ * @param passphrase the passphrase to use
+ * @param msec how many milliseconds to run the PBKDF
+ * @param rng a random number generator
+ */
+ PBE_PKCS5v15(BlockCipher* cipher,
+ HashFunction* hash,
+ const std::string& passphrase,
+ std::chrono::milliseconds msec,
+ RandomNumberGenerator& rng);
+
+ PBE_PKCS5v15(BlockCipher* cipher,
+ HashFunction* hash,
+ const std::vector<byte>& params,
+ const std::string& passphrase);
+
+ ~PBE_PKCS5v15();
+ private:
+
+ void flush_pipe(bool);
+
+ Cipher_Dir m_direction;
+ BlockCipher* m_block_cipher;
+ HashFunction* m_hash_function;
+
+ secure_vector<byte> m_salt, m_key, m_iv;
+ size_t m_iterations;
+ Pipe m_pipe;
+ };
+
+}
+
+#endif
diff --git a/src/lib/pbe/pbes2/info.txt b/src/lib/pbe/pbes2/info.txt
new file mode 100644
index 000000000..ba7d77774
--- /dev/null
+++ b/src/lib/pbe/pbes2/info.txt
@@ -0,0 +1,14 @@
+define PBE_PKCS_V20 20131128
+
+<requires>
+algo_factory
+asn1
+block
+cbc
+filters
+hash
+hmac
+libstate
+oid_lookup
+pbkdf2
+</requires>
diff --git a/src/lib/pbe/pbes2/pbes2.cpp b/src/lib/pbe/pbes2/pbes2.cpp
new file mode 100644
index 000000000..d4df1277c
--- /dev/null
+++ b/src/lib/pbe/pbes2/pbes2.cpp
@@ -0,0 +1,209 @@
+/*
+* PKCS #5 PBES2
+* (C) 1999-2008 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/pbes2.h>
+#include <botan/pbkdf2.h>
+#include <botan/algo_factory.h>
+#include <botan/libstate.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/parsing.h>
+#include <botan/alg_id.h>
+#include <botan/oids.h>
+#include <botan/lookup.h>
+#include <algorithm>
+#include <memory>
+
+namespace Botan {
+
+/*
+* Encrypt some bytes using PBES2
+*/
+void PBE_PKCS5v20::write(const byte input[], size_t length)
+ {
+ pipe.write(input, length);
+ flush_pipe(true);
+ }
+
+/*
+* Start encrypting with PBES2
+*/
+void PBE_PKCS5v20::start_msg()
+ {
+ pipe.append(get_cipher(block_cipher->name() + "/CBC/PKCS7",
+ key, iv, direction));
+
+ pipe.start_msg();
+ if(pipe.message_count() > 1)
+ pipe.set_default_msg(pipe.default_msg() + 1);
+ }
+
+/*
+* Finish encrypting with PBES2
+*/
+void PBE_PKCS5v20::end_msg()
+ {
+ pipe.end_msg();
+ flush_pipe(false);
+ pipe.reset();
+ }
+
+/*
+* Flush the pipe
+*/
+void PBE_PKCS5v20::flush_pipe(bool safe_to_skip)
+ {
+ if(safe_to_skip && pipe.remaining() < 64)
+ return;
+
+ secure_vector<byte> buffer(DEFAULT_BUFFERSIZE);
+ while(pipe.remaining())
+ {
+ const size_t got = pipe.read(&buffer[0], buffer.size());
+ send(buffer, got);
+ }
+ }
+
+/*
+* Encode PKCS#5 PBES2 parameters
+*/
+std::vector<byte> PBE_PKCS5v20::encode_params() const
+ {
+ return DER_Encoder()
+ .start_cons(SEQUENCE)
+ .encode(
+ AlgorithmIdentifier("PKCS5.PBKDF2",
+ DER_Encoder()
+ .start_cons(SEQUENCE)
+ .encode(salt, OCTET_STRING)
+ .encode(iterations)
+ .encode(key_length)
+ .encode_if(
+ m_prf->name() != "HMAC(SHA-160)",
+ AlgorithmIdentifier(m_prf->name(),
+ AlgorithmIdentifier::USE_NULL_PARAM))
+ .end_cons()
+ .get_contents_unlocked()
+ )
+ )
+ .encode(
+ AlgorithmIdentifier(block_cipher->name() + "/CBC",
+ DER_Encoder().encode(iv, OCTET_STRING).get_contents_unlocked()
+ )
+ )
+ .end_cons()
+ .get_contents_unlocked();
+ }
+
+/*
+* Return an OID for PBES2
+*/
+OID PBE_PKCS5v20::get_oid() const
+ {
+ return OIDS::lookup("PBE-PKCS5v20");
+ }
+
+std::string PBE_PKCS5v20::name() const
+ {
+ return "PBE-PKCS5v20(" + block_cipher->name() + "," +
+ m_prf->name() + ")";
+ }
+
+/*
+* PKCS#5 v2.0 PBE Constructor
+*/
+PBE_PKCS5v20::PBE_PKCS5v20(BlockCipher* cipher,
+ MessageAuthenticationCode* mac,
+ const std::string& passphrase,
+ std::chrono::milliseconds msec,
+ RandomNumberGenerator& rng) :
+ direction(ENCRYPTION),
+ block_cipher(cipher),
+ m_prf(mac),
+ salt(rng.random_vec(12)),
+ iv(rng.random_vec(block_cipher->block_size())),
+ iterations(0),
+ key_length(block_cipher->maximum_keylength())
+ {
+ PKCS5_PBKDF2 pbkdf(m_prf->clone());
+
+ key = pbkdf.derive_key(key_length, passphrase,
+ &salt[0], salt.size(),
+ msec, iterations).bits_of();
+ }
+
+/*
+* PKCS#5 v2.0 PBE Constructor
+*/
+PBE_PKCS5v20::PBE_PKCS5v20(const std::vector<byte>& params,
+ const std::string& passphrase) :
+ direction(DECRYPTION),
+ block_cipher(nullptr),
+ m_prf(nullptr)
+ {
+ AlgorithmIdentifier kdf_algo, enc_algo;
+
+ BER_Decoder(params)
+ .start_cons(SEQUENCE)
+ .decode(kdf_algo)
+ .decode(enc_algo)
+ .verify_end()
+ .end_cons();
+
+ AlgorithmIdentifier prf_algo;
+
+ if(kdf_algo.oid != OIDS::lookup("PKCS5.PBKDF2"))
+ throw Decoding_Error("PBE-PKCS5 v2.0: Unknown KDF algorithm " +
+ kdf_algo.oid.as_string());
+
+ BER_Decoder(kdf_algo.parameters)
+ .start_cons(SEQUENCE)
+ .decode(salt, OCTET_STRING)
+ .decode(iterations)
+ .decode_optional(key_length, INTEGER, UNIVERSAL)
+ .decode_optional(prf_algo, SEQUENCE, CONSTRUCTED,
+ AlgorithmIdentifier("HMAC(SHA-160)",
+ AlgorithmIdentifier::USE_NULL_PARAM))
+ .verify_end()
+ .end_cons();
+
+ Algorithm_Factory& af = global_state().algorithm_factory();
+
+ std::string cipher = OIDS::lookup(enc_algo.oid);
+ std::vector<std::string> cipher_spec = split_on(cipher, '/');
+ if(cipher_spec.size() != 2)
+ throw Decoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher);
+
+ if(cipher_spec[1] != "CBC")
+ throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " +
+ cipher);
+
+ BER_Decoder(enc_algo.parameters).decode(iv, OCTET_STRING).verify_end();
+
+ block_cipher = af.make_block_cipher(cipher_spec[0]);
+ m_prf = af.make_mac(OIDS::lookup(prf_algo.oid));
+
+ if(key_length == 0)
+ key_length = block_cipher->maximum_keylength();
+
+ if(salt.size() < 8)
+ throw Decoding_Error("PBE-PKCS5 v2.0: Encoded salt is too small");
+
+ PKCS5_PBKDF2 pbkdf(m_prf->clone());
+
+ key = pbkdf.derive_key(key_length, passphrase,
+ &salt[0], salt.size(),
+ iterations).bits_of();
+ }
+
+PBE_PKCS5v20::~PBE_PKCS5v20()
+ {
+ delete m_prf;
+ delete block_cipher;
+ }
+
+}
diff --git a/src/lib/pbe/pbes2/pbes2.h b/src/lib/pbe/pbes2/pbes2.h
new file mode 100644
index 000000000..b7160f575
--- /dev/null
+++ b/src/lib/pbe/pbes2/pbes2.h
@@ -0,0 +1,70 @@
+/*
+* PKCS #5 v2.0 PBE
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_PBE_PKCS_v20_H__
+#define BOTAN_PBE_PKCS_v20_H__
+
+#include <botan/pbe.h>
+#include <botan/block_cipher.h>
+#include <botan/mac.h>
+#include <botan/pipe.h>
+#include <chrono>
+
+namespace Botan {
+
+/**
+* PKCS #5 v2.0 PBE
+*/
+class BOTAN_DLL PBE_PKCS5v20 : public PBE
+ {
+ public:
+ OID get_oid() const;
+
+ std::vector<byte> encode_params() const;
+
+ std::string name() const;
+
+ void write(const byte buf[], size_t buf_len);
+ void start_msg();
+ void end_msg();
+
+ /**
+ * Load a PKCS #5 v2.0 encrypted stream
+ * @param params the PBES2 parameters
+ * @param passphrase the passphrase to use for decryption
+ */
+ PBE_PKCS5v20(const std::vector<byte>& params,
+ const std::string& passphrase);
+
+ /**
+ * @param cipher the block cipher to use
+ * @param mac the MAC to use
+ * @param passphrase the passphrase to use for encryption
+ * @param msec how many milliseconds to run the PBKDF
+ * @param rng a random number generator
+ */
+ PBE_PKCS5v20(BlockCipher* cipher,
+ MessageAuthenticationCode* mac,
+ const std::string& passphrase,
+ std::chrono::milliseconds msec,
+ RandomNumberGenerator& rng);
+
+ ~PBE_PKCS5v20();
+ private:
+ void flush_pipe(bool);
+
+ Cipher_Dir direction;
+ BlockCipher* block_cipher;
+ MessageAuthenticationCode* m_prf;
+ secure_vector<byte> salt, key, iv;
+ size_t iterations, key_length;
+ Pipe pipe;
+ };
+
+}
+
+#endif