diff options
author | lloyd <[email protected]> | 2012-05-31 18:19:43 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2012-05-31 18:19:43 +0000 |
commit | b82642c328d98f2aaa1ac17aa0999e69e7152ae8 (patch) | |
tree | a2a181c26709bd7995d519c9148c6f0bc06f143f /src/pbe | |
parent | 75db296a459a9e25b112207707cc5e26a6f2b872 (diff) |
Add new PBKDF interface that takes a std::chrono::milliseconds and
runs the KDF until at least that much time has passed, then returns
the number of interations used.
New parameter to the PKCS8 encryption routines which tells how long to
run the PBKDF. Defaults to 200 milliseconds, which is short enough
that it is unlikely to bother anyone but long enough to provide quite
reasonable security against cracking attacks. On a Core i7-860, 200
ms with PBKDF2/SHA-1 runs about 180K to 220K iterations (compare with
previous default of 10K).
New PBE interface, remove new_params/set_key and require all inputs
including the passphrase to be passed to the constructor.
Drop the PGP S2K as it is pretty weird and not really useful outside
of a full PGP implementation.
Drop the deprecated PKCS8::encrypt_key and PKCS8::encode functions.
Diffstat (limited to 'src/pbe')
-rw-r--r-- | src/pbe/get_pbe.cpp | 29 | ||||
-rw-r--r-- | src/pbe/get_pbe.h | 9 | ||||
-rw-r--r-- | src/pbe/pbe.h | 18 | ||||
-rw-r--r-- | src/pbe/pbes1/pbes1.cpp | 155 | ||||
-rw-r--r-- | src/pbe/pbes1/pbes1.h | 31 | ||||
-rw-r--r-- | src/pbe/pbes2/pbes2.cpp | 142 | ||||
-rw-r--r-- | src/pbe/pbes2/pbes2.h | 19 |
7 files changed, 207 insertions, 196 deletions
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; |