aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/engine/core_engine/lookup_pbkdf.cpp9
-rw-r--r--src/pbe/get_pbe.cpp29
-rw-r--r--src/pbe/get_pbe.h9
-rw-r--r--src/pbe/pbe.h18
-rw-r--r--src/pbe/pbes1/pbes1.cpp155
-rw-r--r--src/pbe/pbes1/pbes1.h31
-rw-r--r--src/pbe/pbes2/pbes2.cpp142
-rw-r--r--src/pbe/pbes2/pbes2.h19
-rw-r--r--src/pbkdf/pbkdf.h44
-rw-r--r--src/pbkdf/pbkdf1/pbkdf1.cpp38
-rw-r--r--src/pbkdf/pbkdf1/pbkdf1.h10
-rw-r--r--src/pbkdf/pbkdf2/pbkdf2.cpp67
-rw-r--r--src/pbkdf/pbkdf2/pbkdf2.h16
-rw-r--r--src/pbkdf/pgps2k/info.txt5
-rw-r--r--src/pbkdf/pgps2k/pgp_s2k.cpp57
-rw-r--r--src/pbkdf/pgps2k/pgp_s2k.h49
-rw-r--r--src/pubkey/pkcs8.cpp29
-rw-r--r--src/pubkey/pkcs8.h70
18 files changed, 373 insertions, 424 deletions
diff --git a/src/engine/core_engine/lookup_pbkdf.cpp b/src/engine/core_engine/lookup_pbkdf.cpp
index 2419f4373..bfd2c8bc2 100644
--- a/src/engine/core_engine/lookup_pbkdf.cpp
+++ b/src/engine/core_engine/lookup_pbkdf.cpp
@@ -17,10 +17,6 @@
#include <botan/pbkdf2.h>
#endif
-#if defined(BOTAN_HAS_PGPS2K)
- #include <botan/pgp_s2k.h>
-#endif
-
namespace Botan {
PBKDF* Core_Engine::find_pbkdf(const SCAN_Name& algo_spec,
@@ -41,11 +37,6 @@ PBKDF* Core_Engine::find_pbkdf(const SCAN_Name& algo_spec,
}
#endif
-#if defined(BOTAN_HAS_PGPS2K)
- if(algo_spec.algo_name() == "OpenPGP-S2K" && algo_spec.arg_count() == 1)
- return new OpenPGP_S2K(af.make_hash_function(algo_spec.arg(0)));
-#endif
-
return nullptr;
}
diff --git a/src/pbe/get_pbe.cpp b/src/pbe/get_pbe.cpp
index 3217101ef..9ce830639 100644
--- a/src/pbe/get_pbe.cpp
+++ b/src/pbe/get_pbe.cpp
@@ -24,7 +24,10 @@ namespace Botan {
/*
* Get an encryption PBE, set new parameters
*/
-PBE* get_pbe(const std::string& algo_spec)
+PBE* get_pbe(const std::string& algo_spec,
+ const std::string& passphrase,
+ std::chrono::milliseconds msec,
+ RandomNumberGenerator& rng)
{
SCAN_Name request(algo_spec);
@@ -59,13 +62,18 @@ PBE* get_pbe(const std::string& algo_spec)
if(pbe == "PBE-PKCS5v15")
return new PBE_PKCS5v15(block_cipher->clone(),
hash_function->clone(),
- ENCRYPTION);
+ passphrase,
+ msec,
+ rng);
#endif
#if defined(BOTAN_HAS_PBE_PKCS_V20)
if(pbe == "PBE-PKCS5v20")
return new PBE_PKCS5v20(block_cipher->clone(),
- hash_function->clone());
+ hash_function->clone(),
+ passphrase,
+ msec,
+ rng);
#endif
throw Algorithm_Not_Found(algo_spec);
@@ -74,7 +82,9 @@ PBE* get_pbe(const std::string& algo_spec)
/*
* Get a decryption PBE, decode parameters
*/
-PBE* get_pbe(const OID& pbe_oid, DataSource& params)
+PBE* get_pbe(const OID& pbe_oid,
+ const std::vector<byte>& params,
+ const std::string& passphrase)
{
SCAN_Name request(OIDS::lookup(pbe_oid));
@@ -111,17 +121,16 @@ PBE* get_pbe(const OID& pbe_oid, DataSource& params)
if(!hash_function)
throw Algorithm_Not_Found(digest_name);
- PBE* pbe = new PBE_PKCS5v15(block_cipher->clone(),
- hash_function->clone(),
- DECRYPTION);
- pbe->decode_params(params);
- return pbe;
+ 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);
+ return new PBE_PKCS5v20(params, passphrase);
#endif
throw Algorithm_Not_Found(pbe_oid.as_string());
diff --git a/src/pbe/get_pbe.h b/src/pbe/get_pbe.h
index 73c53497c..719b92c30 100644
--- a/src/pbe/get_pbe.h
+++ b/src/pbe/get_pbe.h
@@ -9,6 +9,7 @@
#define BOTAN_LOOKUP_PBE_H__
#include <botan/pbe.h>
+#include <vector>
#include <string>
namespace Botan {
@@ -18,7 +19,10 @@ namespace Botan {
* @param algo_spec the name of the PBE algorithm to retrieve
* @return pointer to a PBE with randomly created parameters
*/
-BOTAN_DLL PBE* get_pbe(const std::string& algo_spec);
+BOTAN_DLL PBE* get_pbe(const std::string& algo_spec,
+ const std::string& passphrase,
+ std::chrono::milliseconds msec,
+ RandomNumberGenerator& rng);
/**
* Factory function for PBEs.
@@ -27,7 +31,8 @@ BOTAN_DLL PBE* get_pbe(const std::string& algo_spec);
* @return pointer to the PBE with the specified parameters
*/
BOTAN_DLL PBE* get_pbe(const OID& pbe_oid,
- DataSource& params);
+ const std::vector<byte>& params,
+ const std::string& password);
}
diff --git a/src/pbe/pbe.h b/src/pbe/pbe.h
index 975f3e6c7..45c98e2c8 100644
--- a/src/pbe/pbe.h
+++ b/src/pbe/pbe.h
@@ -22,30 +22,12 @@ class BOTAN_DLL PBE : public Filter
{
public:
/**
- * Set this filter's key.
- * @param pw the password to be used for the encryption
- */
- virtual void set_key(const std::string& pw) = 0;
-
- /**
- * Create a new random salt value and set the default iterations value.
- * @param rng a random number generator
- */
- virtual void new_params(RandomNumberGenerator& rng) = 0;
-
- /**
* DER encode the params (the number of iterations and the salt value)
* @return encoded params
*/
virtual std::vector<byte> encode_params() const = 0;
/**
- * Decode params and use them inside this Filter.
- * @param src a data source to read the encoded params from
- */
- virtual void decode_params(DataSource& src) = 0;
-
- /**
* Get this PBE's OID.
* @return object identifier
*/
diff --git a/src/pbe/pbes1/pbes1.cpp b/src/pbe/pbes1/pbes1.cpp
index 41a793a24..e86a496ac 100644
--- a/src/pbe/pbes1/pbes1.cpp
+++ b/src/pbe/pbes1/pbes1.cpp
@@ -19,7 +19,7 @@ namespace Botan {
*/
void PBE_PKCS5v15::write(const byte input[], size_t length)
{
- pipe.write(input, length);
+ m_pipe.write(input, length);
flush_pipe(true);
}
@@ -28,18 +28,18 @@ void PBE_PKCS5v15::write(const byte input[], size_t length)
*/
void PBE_PKCS5v15::start_msg()
{
- if(direction == ENCRYPTION)
- pipe.append(new CBC_Encryption(block_cipher->clone(),
- new PKCS7_Padding,
- key, iv));
+ if(m_direction == ENCRYPTION)
+ m_pipe.append(new CBC_Encryption(m_block_cipher->clone(),
+ new PKCS7_Padding,
+ m_key, m_iv));
else
- pipe.append(new CBC_Decryption(block_cipher->clone(),
- new PKCS7_Padding,
- key, iv));
+ m_pipe.append(new CBC_Decryption(m_block_cipher->clone(),
+ new PKCS7_Padding,
+ m_key, m_iv));
- pipe.start_msg();
- if(pipe.message_count() > 1)
- pipe.set_default_msg(pipe.default_msg() + 1);
+ m_pipe.start_msg();
+ if(m_pipe.message_count() > 1)
+ m_pipe.set_default_msg(m_pipe.default_msg() + 1);
}
/*
@@ -47,9 +47,9 @@ void PBE_PKCS5v15::start_msg()
*/
void PBE_PKCS5v15::end_msg()
{
- pipe.end_msg();
+ m_pipe.end_msg();
flush_pipe(false);
- pipe.reset();
+ m_pipe.reset();
}
/*
@@ -57,81 +57,39 @@ void PBE_PKCS5v15::end_msg()
*/
void PBE_PKCS5v15::flush_pipe(bool safe_to_skip)
{
- if(safe_to_skip && pipe.remaining() < 64)
+ if(safe_to_skip && m_pipe.remaining() < 64)
return;
secure_vector<byte> buffer(DEFAULT_BUFFERSIZE);
- while(pipe.remaining())
+ while(m_pipe.remaining())
{
- size_t got = pipe.read(&buffer[0], buffer.size());
+ size_t got = m_pipe.read(&buffer[0], buffer.size());
send(buffer, got);
}
}
/*
-* Set the passphrase to use
-*/
-void PBE_PKCS5v15::set_key(const std::string& passphrase)
- {
- PKCS5_PBKDF1 pbkdf(hash_function->clone());
-
- secure_vector<byte> key_and_iv = pbkdf.derive_key(16, passphrase,
- &salt[0], salt.size(),
- iterations).bits_of();
-
- key.resize(8);
- iv.resize(8);
- copy_mem(&key[0], &key_and_iv[0], 8);
- copy_mem(&iv[0], &key_and_iv[8], 8);
- }
-
-/*
-* Create a new set of PBES1 parameters
-*/
-void PBE_PKCS5v15::new_params(RandomNumberGenerator& rng)
- {
- iterations = 10000;
- salt = rng.random_vec(8);
- }
-
-/*
* Encode PKCS#5 PBES1 parameters
*/
std::vector<byte> PBE_PKCS5v15::encode_params() const
{
return DER_Encoder()
.start_cons(SEQUENCE)
- .encode(salt, OCTET_STRING)
- .encode(iterations)
+ .encode(m_salt, OCTET_STRING)
+ .encode(m_iterations)
.end_cons()
.get_contents_unlocked();
}
/*
-* Decode PKCS#5 PBES1 parameters
-*/
-void PBE_PKCS5v15::decode_params(DataSource& source)
- {
- BER_Decoder(source)
- .start_cons(SEQUENCE)
- .decode(salt, OCTET_STRING)
- .decode(iterations)
- .verify_end()
- .end_cons();
-
- if(salt.size() != 8)
- throw Decoding_Error("PBES1: Encoded salt is not 8 octets");
- }
-
-/*
* 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 = block_cipher->name();
- const std::string digest = hash_function->name();
+ 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);
@@ -151,17 +109,52 @@ OID PBE_PKCS5v15::get_oid() const
std::string PBE_PKCS5v15::name() const
{
- return "PBE-PKCS5v15(" + block_cipher->name() + "," +
- hash_function->name() + ")";
+ 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]);
+
}
-/*
-* PKCS#5 v1.5 PBE Constructor
-*/
PBE_PKCS5v15::PBE_PKCS5v15(BlockCipher* cipher,
HashFunction* hash,
- Cipher_Dir dir) :
- direction(dir), block_cipher(cipher), hash_function(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")
{
@@ -175,12 +168,32 @@ PBE_PKCS5v15::PBE_PKCS5v15(BlockCipher* cipher,
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 block_cipher;
- delete hash_function;
+ delete m_block_cipher;
+ delete m_hash_function;
}
}
diff --git a/src/pbe/pbes1/pbes1.h b/src/pbe/pbes1/pbes1.h
index bbdbd5b9d..0c921dadd 100644
--- a/src/pbe/pbes1/pbes1.h
+++ b/src/pbe/pbes1/pbes1.h
@@ -21,6 +21,10 @@ namespace Botan {
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);
@@ -30,29 +34,30 @@ class BOTAN_DLL PBE_PKCS5v15 : public PBE
/**
* @param cipher the block cipher to use (DES or RC2)
* @param hash the hash function to use
- * @param direction are we encrypting or decrypting
*/
PBE_PKCS5v15(BlockCipher* cipher,
HashFunction* hash,
- Cipher_Dir direction);
+ 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 set_key(const std::string&);
- void new_params(RandomNumberGenerator& rng);
- std::vector<byte> encode_params() const;
- void decode_params(DataSource&);
- OID get_oid() const;
void flush_pipe(bool);
- Cipher_Dir direction;
- BlockCipher* block_cipher;
- HashFunction* hash_function;
+ Cipher_Dir m_direction;
+ BlockCipher* m_block_cipher;
+ HashFunction* m_hash_function;
- secure_vector<byte> salt, key, iv;
- size_t iterations;
- Pipe pipe;
+ secure_vector<byte> m_salt, m_key, m_iv;
+ size_t m_iterations;
+ Pipe m_pipe;
};
}
diff --git a/src/pbe/pbes2/pbes2.cpp b/src/pbe/pbes2/pbes2.cpp
index 0036359cc..dc8ffbbcd 100644
--- a/src/pbe/pbes2/pbes2.cpp
+++ b/src/pbe/pbes2/pbes2.cpp
@@ -76,30 +76,6 @@ void PBE_PKCS5v20::flush_pipe(bool safe_to_skip)
}
/*
-* Set the passphrase to use
-*/
-void PBE_PKCS5v20::set_key(const std::string& passphrase)
- {
- PKCS5_PBKDF2 pbkdf(new HMAC(hash_function->clone()));
-
- key = pbkdf.derive_key(key_length, passphrase,
- &salt[0], salt.size(),
- iterations).bits_of();
- }
-
-/*
-* Create a new set of PBES2 parameters
-*/
-void PBE_PKCS5v20::new_params(RandomNumberGenerator& rng)
- {
- iterations = 10000;
- key_length = block_cipher->maximum_keylength();
-
- salt = rng.random_vec(12);
- iv = rng.random_vec(block_cipher->block_size());
- }
-
-/*
* Encode PKCS#5 PBES2 parameters
*/
std::vector<byte> PBE_PKCS5v20::encode_params() const
@@ -129,13 +105,74 @@ std::vector<byte> PBE_PKCS5v20::encode_params() const
}
/*
-* Decode PKCS#5 PBES2 parameters
+* Return an OID for PBES2
+*/
+OID PBE_PKCS5v20::get_oid() const
+ {
+ return OIDS::lookup("PBE-PKCS5v20");
+ }
+
+/*
+* Check if this is a known PBES2 cipher
+*/
+bool PBE_PKCS5v20::known_cipher(const std::string& algo)
+ {
+ if(algo == "AES-128" || algo == "AES-192" || algo == "AES-256")
+ return true;
+
+ if(algo == "DES" || algo == "TripleDES")
+ return true;
+
+ return false;
+ }
+
+std::string PBE_PKCS5v20::name() const
+ {
+ return "PBE-PKCS5v20(" + block_cipher->name() + "," +
+ hash_function->name() + ")";
+ }
+
+/*
+* PKCS#5 v2.0 PBE Constructor
*/
-void PBE_PKCS5v20::decode_params(DataSource& source)
+PBE_PKCS5v20::PBE_PKCS5v20(BlockCipher* cipher,
+ HashFunction* digest,
+ const std::string& passphrase,
+ std::chrono::milliseconds msec,
+ RandomNumberGenerator& rng) :
+ direction(ENCRYPTION),
+ block_cipher(cipher),
+ hash_function(digest),
+ salt(rng.random_vec(12)),
+ iv(rng.random_vec(block_cipher->block_size())),
+ iterations(0),
+ key_length(block_cipher->maximum_keylength())
{
+ if(!known_cipher(block_cipher->name()))
+ throw Invalid_Argument("PBE-PKCS5 v2.0: Invalid cipher " + cipher->name());
+ if(hash_function->name() != "SHA-160")
+ throw Invalid_Argument("PBE-PKCS5 v2.0: Invalid digest " + digest->name());
+
+ PKCS5_PBKDF2 pbkdf(new HMAC(hash_function->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)
+ {
+ hash_function = nullptr;
+ block_cipher = nullptr;
+
AlgorithmIdentifier kdf_algo, enc_algo;
- BER_Decoder(source)
+ BER_Decoder(params)
.start_cons(SEQUENCE)
.decode(kdf_algo)
.decode(enc_algo)
@@ -177,55 +214,12 @@ void PBE_PKCS5v20::decode_params(DataSource& source)
if(salt.size() < 8)
throw Decoding_Error("PBE-PKCS5 v2.0: Encoded salt is too small");
- }
-
-/*
-* Return an OID for PBES2
-*/
-OID PBE_PKCS5v20::get_oid() const
- {
- return OIDS::lookup("PBE-PKCS5v20");
- }
-/*
-* Check if this is a known PBES2 cipher
-*/
-bool PBE_PKCS5v20::known_cipher(const std::string& algo)
- {
- if(algo == "AES-128" || algo == "AES-192" || algo == "AES-256")
- return true;
- if(algo == "DES" || algo == "TripleDES")
- return true;
- return false;
- }
-
-std::string PBE_PKCS5v20::name() const
- {
- return "PBE-PKCS5v20(" + block_cipher->name() + "," +
- hash_function->name() + ")";
- }
-
-/*
-* PKCS#5 v2.0 PBE Constructor
-*/
-PBE_PKCS5v20::PBE_PKCS5v20(BlockCipher* cipher,
- HashFunction* digest) :
- direction(ENCRYPTION), block_cipher(cipher), hash_function(digest)
- {
- if(!known_cipher(block_cipher->name()))
- throw Invalid_Argument("PBE-PKCS5 v2.0: Invalid cipher " + cipher->name());
- if(hash_function->name() != "SHA-160")
- throw Invalid_Argument("PBE-PKCS5 v2.0: Invalid digest " + digest->name());
- }
+ PKCS5_PBKDF2 pbkdf(new HMAC(hash_function->clone()));
-/*
-* PKCS#5 v2.0 PBE Constructor
-*/
-PBE_PKCS5v20::PBE_PKCS5v20(DataSource& params) : direction(DECRYPTION)
- {
- hash_function = nullptr;
- block_cipher = nullptr;
- decode_params(params);
+ key = pbkdf.derive_key(key_length, passphrase,
+ &salt[0], salt.size(),
+ iterations).bits_of();
}
PBE_PKCS5v20::~PBE_PKCS5v20()
diff --git a/src/pbe/pbes2/pbes2.h b/src/pbe/pbes2/pbes2.h
index 5593c9091..635837b42 100644
--- a/src/pbe/pbes2/pbes2.h
+++ b/src/pbe/pbes2/pbes2.h
@@ -27,6 +27,10 @@ class BOTAN_DLL PBE_PKCS5v20 : public PBE
*/
static bool known_cipher(const std::string& cipher);
+ OID get_oid() const;
+
+ std::vector<byte> encode_params() const;
+
std::string name() const;
void write(const byte[], size_t);
@@ -37,22 +41,21 @@ class BOTAN_DLL PBE_PKCS5v20 : public PBE
* Load a PKCS #5 v2.0 encrypted stream
* @param input is the input source
*/
- PBE_PKCS5v20(DataSource& input);
+ PBE_PKCS5v20(const std::vector<byte>& params,
+ const std::string& passphrase);
/**
* @param cipher the block cipher to use
* @param hash the hash function to use
*/
- PBE_PKCS5v20(BlockCipher* cipher, HashFunction* hash);
+ PBE_PKCS5v20(BlockCipher* cipher,
+ HashFunction* hash,
+ const std::string& passphrase,
+ std::chrono::milliseconds msec,
+ RandomNumberGenerator& rng);
~PBE_PKCS5v20();
private:
- void set_key(const std::string&);
- void new_params(RandomNumberGenerator& rng);
- std::vector<byte> encode_params() const;
- void decode_params(DataSource&);
- OID get_oid() const;
-
void flush_pipe(bool);
Cipher_Dir direction;
diff --git a/src/pbkdf/pbkdf.h b/src/pbkdf/pbkdf.h
index e951b5673..176ed0302 100644
--- a/src/pbkdf/pbkdf.h
+++ b/src/pbkdf/pbkdf.h
@@ -1,6 +1,6 @@
/*
* PBKDF
-* (C) 1999-2007 Jack Lloyd
+* (C) 1999-2007,2012 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
@@ -10,6 +10,7 @@
#include <botan/algo_base.h>
#include <botan/symkey.h>
+#include <chrono>
namespace Botan {
@@ -37,10 +38,43 @@ class BOTAN_DLL PBKDF : public Algorithm
* @param salt_len length of salt in bytes
* @param iterations the number of iterations to use (use 10K or more)
*/
- virtual OctetString derive_key(size_t output_len,
- const std::string& passphrase,
- const byte salt[], size_t salt_len,
- size_t iterations) const = 0;
+ OctetString derive_key(size_t output_len,
+ const std::string& passphrase,
+ const byte salt[], size_t salt_len,
+ size_t iterations) const;
+
+ /**
+ * Derive a key from a passphrase
+ * @param output_len the desired length of the key to produce
+ * @param passphrase the password to derive the key from
+ * @param salt a randomly chosen salt
+ * @param salt_len length of salt in bytes
+ * @param msec is how long to run the PBKDF
+ * @param iterations is set to the number of iterations used
+ */
+ OctetString derive_key(size_t output_len,
+ const std::string& passphrase,
+ const byte salt[], size_t salt_len,
+ std::chrono::milliseconds msec,
+ size_t& iterations) const;
+
+ /**
+ * Derive a key from a passphrase for a number of iterations
+ * specified by either iterations or if iterations == 0 then
+ * running until seconds time has elapsed.
+ *
+ * @param output_len the desired length of the key to produce
+ * @param passphrase the password to derive the key from
+ * @param salt a randomly chosen salt
+ * @param salt_len length of salt in bytes
+ * @param iterations the number of iterations to use (use 10K or more)
+ */
+ virtual std::pair<size_t, OctetString>
+ key_derivation(size_t output_len,
+ const std::string& passphrase,
+ const byte salt[], size_t salt_len,
+ size_t iterations,
+ std::chrono::milliseconds msec) const = 0;
};
/**
diff --git a/src/pbkdf/pbkdf1/pbkdf1.cpp b/src/pbkdf/pbkdf1/pbkdf1.cpp
index 7f0939b8f..d51cbdc18 100644
--- a/src/pbkdf/pbkdf1/pbkdf1.cpp
+++ b/src/pbkdf/pbkdf1/pbkdf1.cpp
@@ -13,28 +13,46 @@ namespace Botan {
/*
* Return a PKCS#5 PBKDF1 derived key
*/
-OctetString PKCS5_PBKDF1::derive_key(size_t key_len,
- const std::string& passphrase,
- const byte salt[], size_t salt_size,
- size_t iterations) const
+std::pair<size_t, OctetString>
+PKCS5_PBKDF1::key_derivation(size_t key_len,
+ const std::string& passphrase,
+ const byte salt[], size_t salt_len,
+ size_t iterations,
+ std::chrono::milliseconds msec) const
{
- if(iterations == 0)
- throw Invalid_Argument("PKCS5_PBKDF1: Invalid iteration count");
-
if(key_len > hash->output_length())
throw Invalid_Argument("PKCS5_PBKDF1: Requested output length too long");
hash->update(passphrase);
- hash->update(salt, salt_size);
+ hash->update(salt, salt_len);
secure_vector<byte> key = hash->final();
- for(size_t j = 1; j != iterations; ++j)
+ const auto start = std::chrono::high_resolution_clock::now();
+ size_t iterations_performed = 1;
+
+ while(true)
{
+ if(iterations == 0)
+ {
+ if(iterations_performed % 8192 == 0)
+ {
+ auto time_taken = std::chrono::high_resolution_clock::now() - start;
+ auto msec_taken = std::chrono::duration_cast<std::chrono::milliseconds>(time_taken);
+ if(msec_taken > msec)
+ break;
+ }
+ }
+ else if(iterations_performed == iterations)
+ break;
+
hash->update(key);
hash->final(&key[0]);
+
+ ++iterations_performed;
}
- return OctetString(&key[0], std::min<size_t>(key_len, key.size()));
+ return std::make_pair(iterations_performed,
+ OctetString(&key[0], std::min(key_len, key.size())));
}
}
diff --git a/src/pbkdf/pbkdf1/pbkdf1.h b/src/pbkdf/pbkdf1/pbkdf1.h
index f8e2dbe69..783b70ed9 100644
--- a/src/pbkdf/pbkdf1/pbkdf1.h
+++ b/src/pbkdf/pbkdf1/pbkdf1.h
@@ -46,10 +46,12 @@ class BOTAN_DLL PKCS5_PBKDF1 : public PBKDF
return new PKCS5_PBKDF1(hash->clone());
}
- OctetString derive_key(size_t output_len,
- const std::string& passphrase,
- const byte salt[], size_t salt_len,
- size_t iterations) const;
+ std::pair<size_t, OctetString>
+ key_derivation(size_t output_len,
+ const std::string& passphrase,
+ const byte salt[], size_t salt_len,
+ size_t iterations,
+ std::chrono::milliseconds msec) const override;
private:
HashFunction* hash;
};
diff --git a/src/pbkdf/pbkdf2/pbkdf2.cpp b/src/pbkdf/pbkdf2/pbkdf2.cpp
index 699ce7c6b..c116b10ab 100644
--- a/src/pbkdf/pbkdf2/pbkdf2.cpp
+++ b/src/pbkdf/pbkdf2/pbkdf2.cpp
@@ -8,19 +8,22 @@
#include <botan/pbkdf2.h>
#include <botan/get_byte.h>
#include <botan/internal/xor_buf.h>
+#include <botan/internal/rounding.h>
namespace Botan {
/*
* Return a PKCS #5 PBKDF2 derived key
*/
-OctetString PKCS5_PBKDF2::derive_key(size_t key_len,
- const std::string& passphrase,
- const byte salt[], size_t salt_size,
- size_t iterations) const
+std::pair<size_t, OctetString>
+PKCS5_PBKDF2::key_derivation(size_t key_len,
+ const std::string& passphrase,
+ const byte salt[], size_t salt_len,
+ size_t iterations,
+ std::chrono::milliseconds msec) const
{
- if(iterations == 0)
- throw Invalid_Argument("PKCS#5 PBKDF2: Invalid iteration count");
+ if(key_len == 0)
+ return std::make_pair(iterations, OctetString());
try
{
@@ -39,22 +42,62 @@ OctetString PKCS5_PBKDF2::derive_key(size_t key_len,
secure_vector<byte> U(mac->output_length());
+ const size_t blocks_needed = round_up(key_len, mac->output_length()) / mac->output_length();
+
+ std::chrono::microseconds usec_per_block =
+ std::chrono::duration_cast<std::chrono::microseconds>(msec) / blocks_needed;
+
u32bit counter = 1;
while(key_len)
{
size_t T_size = std::min<size_t>(mac->output_length(), key_len);
- mac->update(salt, salt_size);
+ mac->update(salt, salt_len);
mac->update_be(counter);
mac->final(&U[0]);
xor_buf(T, &U[0], T_size);
- for(size_t j = 1; j != iterations; ++j)
+ if(iterations == 0)
+ {
+ /*
+ If no iterations set, run the first block to calibrate based
+ on how long hashing takes on whatever machine we're running on.
+ */
+
+ const auto start = std::chrono::high_resolution_clock::now();
+
+ iterations = 1; // the first iteration we did above
+
+ while(true)
+ {
+ mac->update(U);
+ mac->final(&U[0]);
+ xor_buf(T, &U[0], T_size);
+ iterations++;
+
+ /*
+ Only break on relatively 'even' iterations. For one it
+ avoids confusion, and likely some broken implementations
+ break on getting completely randomly distributed values
+ */
+ if(iterations % 8192 == 0)
+ {
+ auto time_taken = std::chrono::high_resolution_clock::now() - start;
+ auto usec_taken = std::chrono::duration_cast<std::chrono::microseconds>(time_taken);
+ if(usec_taken > usec_per_block)
+ break;
+ }
+ }
+ }
+ else
{
- mac->update(U);
- mac->final(&U[0]);
- xor_buf(T, &U[0], T_size);
+ for(size_t i = 1; i != iterations; ++i)
+ {
+ mac->update(U);
+ mac->final(&U[0]);
+ xor_buf(T, &U[0], T_size);
+ }
}
key_len -= T_size;
@@ -62,7 +105,7 @@ OctetString PKCS5_PBKDF2::derive_key(size_t key_len,
++counter;
}
- return key;
+ return std::make_pair(iterations, key);
}
}
diff --git a/src/pbkdf/pbkdf2/pbkdf2.h b/src/pbkdf/pbkdf2/pbkdf2.h
index 26392bdad..8bc271fcf 100644
--- a/src/pbkdf/pbkdf2/pbkdf2.h
+++ b/src/pbkdf/pbkdf2/pbkdf2.h
@@ -1,6 +1,6 @@
/*
* PBKDF2
-* (C) 1999-2007 Jack Lloyd
+* (C) 1999-2007,2012 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
@@ -19,20 +19,22 @@ namespace Botan {
class BOTAN_DLL PKCS5_PBKDF2 : public PBKDF
{
public:
- std::string name() const
+ std::string name() const override
{
return "PBKDF2(" + mac->name() + ")";
}
- PBKDF* clone() const
+ PBKDF* clone() const override
{
return new PKCS5_PBKDF2(mac->clone());
}
- OctetString derive_key(size_t output_len,
- const std::string& passphrase,
- const byte salt[], size_t salt_len,
- size_t iterations) const;
+ std::pair<size_t, OctetString>
+ key_derivation(size_t output_len,
+ const std::string& passphrase,
+ const byte salt[], size_t salt_len,
+ size_t iterations,
+ std::chrono::milliseconds msec) const override;
/**
* Create a PKCS #5 instance using the specified message auth code
diff --git a/src/pbkdf/pgps2k/info.txt b/src/pbkdf/pgps2k/info.txt
deleted file mode 100644
index 8be9c79f8..000000000
--- a/src/pbkdf/pgps2k/info.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-define PGPS2K
-
-<requires>
-hash
-</requires>
diff --git a/src/pbkdf/pgps2k/pgp_s2k.cpp b/src/pbkdf/pgps2k/pgp_s2k.cpp
deleted file mode 100644
index 6f6de58e2..000000000
--- a/src/pbkdf/pgps2k/pgp_s2k.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-* OpenPGP S2K
-* (C) 1999-2007 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#include <botan/pgp_s2k.h>
-
-namespace Botan {
-
-/*
-* Derive a key using the OpenPGP S2K algorithm
-*/
-OctetString OpenPGP_S2K::derive_key(size_t key_len,
- const std::string& passphrase,
- const byte salt_buf[], size_t salt_size,
- size_t iterations) const
- {
- secure_vector<byte> key(key_len), hash_buf;
-
- size_t pass = 0, generated = 0,
- total_size = passphrase.size() + salt_size;
- size_t to_hash = std::max(iterations, total_size);
-
- hash->clear();
- while(key_len > generated)
- {
- for(size_t j = 0; j != pass; ++j)
- hash->update(0);
-
- size_t left = to_hash;
- while(left >= total_size)
- {
- hash->update(salt_buf, salt_size);
- hash->update(passphrase);
- left -= total_size;
- }
- if(left <= salt_size)
- hash->update(salt_buf, left);
- else
- {
- hash->update(salt_buf, salt_size);
- left -= salt_size;
- hash->update(reinterpret_cast<const byte*>(passphrase.data()), left);
- }
-
- hash_buf = hash->final();
- buffer_insert(key, generated, &hash_buf[0], hash->output_length());
- generated += hash->output_length();
- ++pass;
- }
-
- return key;
- }
-
-}
diff --git a/src/pbkdf/pgps2k/pgp_s2k.h b/src/pbkdf/pgps2k/pgp_s2k.h
deleted file mode 100644
index 7620a6c84..000000000
--- a/src/pbkdf/pgps2k/pgp_s2k.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
-* OpenPGP PBKDF
-* (C) 1999-2007 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#ifndef BOTAN_OPENPGP_S2K_H__
-#define BOTAN_OPENPGP_S2K_H__
-
-#include <botan/pbkdf.h>
-#include <botan/hash.h>
-
-namespace Botan {
-
-/**
-* OpenPGP's S2K
-*/
-class BOTAN_DLL OpenPGP_S2K : public PBKDF
- {
- public:
- /**
- * @param hash_in the hash function to use
- */
- OpenPGP_S2K(HashFunction* hash_in) : hash(hash_in) {}
-
- ~OpenPGP_S2K() { delete hash; }
-
- std::string name() const
- {
- return "OpenPGP-S2K(" + hash->name() + ")";
- }
-
- PBKDF* clone() const
- {
- return new OpenPGP_S2K(hash->clone());
- }
-
- OctetString derive_key(size_t output_len,
- const std::string& passphrase,
- const byte salt[], size_t salt_len,
- size_t iterations) const;
- private:
- HashFunction* hash;
- };
-
-}
-
-#endif
diff --git a/src/pubkey/pkcs8.cpp b/src/pubkey/pkcs8.cpp
index baf6d1250..23c021fdb 100644
--- a/src/pubkey/pkcs8.cpp
+++ b/src/pubkey/pkcs8.cpp
@@ -90,16 +90,12 @@ secure_vector<byte> PKCS8_decode(
if(is_encrypted)
{
- DataSource_Memory params(pbe_alg_id.parameters);
- std::unique_ptr<PBE> pbe(get_pbe(pbe_alg_id.oid, params));
-
std::pair<bool, std::string> pass = get_passphrase();
if(pass.first == false)
break;
- pbe->set_key(pass.second);
- Pipe decryptor(pbe.release());
+ Pipe decryptor(get_pbe(pbe_alg_id.oid, pbe_alg_id.parameters, pass.second));
decryptor.process_msg(key_data);
key = decryptor.read_all();
@@ -155,17 +151,19 @@ std::string PEM_encode(const Private_Key& key)
/*
* BER encode a PKCS #8 private key, encrypted
*/
-secure_vector<byte> BER_encode(const Private_Key& key,
- RandomNumberGenerator& rng,
- const std::string& pass,
- const std::string& pbe_algo)
+std::vector<byte> BER_encode(const Private_Key& key,
+ RandomNumberGenerator& rng,
+ const std::string& pass,
+ std::chrono::milliseconds msec,
+ const std::string& pbe_algo)
{
const std::string DEFAULT_PBE = "PBE-PKCS5v20(SHA-1,AES-256/CBC)";
- std::unique_ptr<PBE> pbe(get_pbe(((pbe_algo != "") ? pbe_algo : DEFAULT_PBE)));
-
- pbe->new_params(rng);
- pbe->set_key(pass);
+ std::unique_ptr<PBE> pbe(
+ get_pbe(((pbe_algo != "") ? pbe_algo : DEFAULT_PBE),
+ pass,
+ msec,
+ rng));
AlgorithmIdentifier pbe_algid(pbe->get_oid(), pbe->encode_params());
@@ -177,7 +175,7 @@ secure_vector<byte> BER_encode(const Private_Key& key,
.encode(pbe_algid)
.encode(key_encrytor.read_all(), OCTET_STRING)
.end_cons()
- .get_contents();
+ .get_contents_unlocked();
}
/*
@@ -186,12 +184,13 @@ secure_vector<byte> BER_encode(const Private_Key& key,
std::string PEM_encode(const Private_Key& key,
RandomNumberGenerator& rng,
const std::string& pass,
+ std::chrono::milliseconds msec,
const std::string& pbe_algo)
{
if(pass == "")
return PEM_encode(key);
- return PEM_Code::encode(PKCS8::BER_encode(key, rng, pass, pbe_algo),
+ return PEM_Code::encode(PKCS8::BER_encode(key, rng, pass, msec, pbe_algo),
"ENCRYPTED PRIVATE KEY");
}
diff --git a/src/pubkey/pkcs8.h b/src/pubkey/pkcs8.h
index fae1633a8..04de723a6 100644
--- a/src/pubkey/pkcs8.h
+++ b/src/pubkey/pkcs8.h
@@ -10,6 +10,7 @@
#include <botan/x509_key.h>
#include <functional>
+#include <chrono>
namespace Botan {
@@ -46,15 +47,18 @@ BOTAN_DLL std::string PEM_encode(const Private_Key& key);
* @param key the key to encode
* @param rng the rng to use
* @param pass the password to use for encryption
+* @param msec number of milliseconds to run the password derivation
* @param pbe_algo the name of the desired password-based encryption
algorithm; if empty ("") a reasonable (portable/secure)
default will be chosen.
* @return encrypted key in binary BER form
*/
-BOTAN_DLL secure_vector<byte> BER_encode(const Private_Key& key,
- RandomNumberGenerator& rng,
- const std::string& pass,
- const std::string& pbe_algo = "");
+BOTAN_DLL std::vector<byte>
+BER_encode(const Private_Key& key,
+ RandomNumberGenerator& rng,
+ const std::string& pass,
+ std::chrono::milliseconds msec = std::chrono::milliseconds(200),
+ const std::string& pbe_algo = "");
/**
* Get a string containing a PEM encoded private key, encrypting it with a
@@ -62,62 +66,18 @@ BOTAN_DLL secure_vector<byte> BER_encode(const Private_Key& key,
* @param key the key to encode
* @param rng the rng to use
* @param pass the password to use for encryption
+* @param msec number of milliseconds to run the password derivation
* @param pbe_algo the name of the desired password-based encryption
algorithm; if empty ("") a reasonable (portable/secure)
default will be chosen.
* @return encrypted key in PEM form
*/
-BOTAN_DLL std::string PEM_encode(const Private_Key& key,
- RandomNumberGenerator& rng,
- const std::string& pass,
- const std::string& pbe_algo = "");
-
-
-/**
-* Encode a private key into a pipe.
-* @deprecated Use PEM_encode or BER_encode instead
-*
-* @param key the private key to encode
-* @param pipe the pipe to feed the encoded key into
-* @param encoding the encoding type to use
-*/
-BOTAN_DEPRECATED("Use PEM_encode or BER_encode")
-inline void encode(const Private_Key& key,
- Pipe& pipe,
- X509_Encoding encoding = PEM)
- {
- if(encoding == PEM)
- pipe.write(PKCS8::PEM_encode(key));
- else
- pipe.write(PKCS8::BER_encode(key));
- }
-
-/**
-* Encode and encrypt a private key into a pipe.
-* @deprecated Use PEM_encode or BER_encode instead
-*
-* @param key the private key to encode
-* @param pipe the pipe to feed the encoded key into
-* @param pass the password to use for encryption
-* @param rng the rng to use
-* @param pbe_algo the name of the desired password-based encryption
- algorithm; if empty ("") a reasonable (portable/secure)
- default will be chosen.
-* @param encoding the encoding type to use
-*/
-BOTAN_DEPRECATED("Use PEM_encode or BER_encode")
-inline void encrypt_key(const Private_Key& key,
- Pipe& pipe,
- RandomNumberGenerator& rng,
- const std::string& pass,
- const std::string& pbe_algo = "",
- X509_Encoding encoding = PEM)
- {
- if(encoding == PEM)
- pipe.write(PKCS8::PEM_encode(key, rng, pass, pbe_algo));
- else
- pipe.write(PKCS8::BER_encode(key, rng, pass, pbe_algo));
- }
+BOTAN_DLL std::string
+PEM_encode(const Private_Key& key,
+ RandomNumberGenerator& rng,
+ const std::string& pass,
+ std::chrono::milliseconds msec = std::chrono::milliseconds(200),
+ const std::string& pbe_algo = "");
/**
* Load a key from a data source.