From 149a855bd7b090eb3868efff272e455e568eade4 Mon Sep 17 00:00:00 2001 From: lloyd Date: Thu, 31 May 2012 21:08:09 +0000 Subject: Allow arbitrary ciphers and hashes with PKCS #5 v2.0. The only requirement is that OIDS for "/CBC" and "HMAC()" are defined. This does assume the normal parameter set of just the IV, so doesn't work right for (IIRC) RC5, but we don't have an OID set for RC5/CBC anyway. Continue to default to SHA-1 plus AES-256 as prior versions of the library can't handle any hashes other than SHA-1 or any ciphers other than AES or DES. OpenSSL 1.0.0j seems to understand SHA-256 + AES-256, though. BER_Decoder::decode_optional was assuming optional values were explicitly tagged. Now, only take that behavior if the input class tag was for a context specific tagging. Remove abort call for debugging from BER_Decoder Add a new version of DER_Encoder::encode_if for single objects. --- src/pbe/pbes2/pbes2.cpp | 76 +++++++++++++++++++------------------------------ src/pbe/pbes2/pbes2.h | 12 ++------ 2 files changed, 33 insertions(+), 55 deletions(-) (limited to 'src/pbe/pbes2') diff --git a/src/pbe/pbes2/pbes2.cpp b/src/pbe/pbes2/pbes2.cpp index dc8ffbbcd..3d9ebc56e 100644 --- a/src/pbe/pbes2/pbes2.cpp +++ b/src/pbe/pbes2/pbes2.cpp @@ -7,7 +7,6 @@ #include #include -#include #include #include #include @@ -89,15 +88,17 @@ std::vector PBE_PKCS5v20::encode_params() const .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() + DER_Encoder().encode(iv, OCTET_STRING).get_contents_unlocked() ) ) .end_cons() @@ -112,48 +113,29 @@ 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() + ")"; + m_prf->name() + ")"; } /* * PKCS#5 v2.0 PBE Constructor */ PBE_PKCS5v20::PBE_PKCS5v20(BlockCipher* cipher, - HashFunction* digest, + MessageAuthenticationCode* mac, const std::string& passphrase, std::chrono::milliseconds msec, RandomNumberGenerator& rng) : direction(ENCRYPTION), block_cipher(cipher), - hash_function(digest), + m_prf(mac), 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())); + PKCS5_PBKDF2 pbkdf(m_prf->clone()); key = pbkdf.derive_key(key_length, passphrase, &salt[0], salt.size(), @@ -165,11 +147,10 @@ PBE_PKCS5v20::PBE_PKCS5v20(BlockCipher* cipher, */ PBE_PKCS5v20::PBE_PKCS5v20(const std::vector& params, const std::string& passphrase) : -direction(DECRYPTION) + direction(DECRYPTION), + block_cipher(nullptr), + m_prf(nullptr) { - hash_function = nullptr; - block_cipher = nullptr; - AlgorithmIdentifier kdf_algo, enc_algo; BER_Decoder(params) @@ -179,20 +160,23 @@ direction(DECRYPTION) .verify_end() .end_cons(); - if(kdf_algo.oid == OIDS::lookup("PKCS5.PBKDF2")) - { - BER_Decoder(kdf_algo.parameters) - .start_cons(SEQUENCE) - .decode(salt, OCTET_STRING) - .decode(iterations) - .decode_optional(key_length, INTEGER, UNIVERSAL) - .verify_end() - .end_cons(); - } - else + 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-1)", + AlgorithmIdentifier::USE_NULL_PARAM)) + .verify_end() + .end_cons(); + Algorithm_Factory& af = global_state().algorithm_factory(); std::string cipher = OIDS::lookup(enc_algo.oid); @@ -200,14 +184,14 @@ direction(DECRYPTION) if(cipher_spec.size() != 2) throw Decoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher); - if(!known_cipher(cipher_spec[0]) || cipher_spec[1] != "CBC") + 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]); - hash_function = af.make_hash_function("SHA-160"); + m_prf = af.make_mac(OIDS::lookup(prf_algo.oid)); if(key_length == 0) key_length = block_cipher->maximum_keylength(); @@ -215,7 +199,7 @@ direction(DECRYPTION) if(salt.size() < 8) throw Decoding_Error("PBE-PKCS5 v2.0: Encoded salt is too small"); - PKCS5_PBKDF2 pbkdf(new HMAC(hash_function->clone())); + PKCS5_PBKDF2 pbkdf(m_prf->clone()); key = pbkdf.derive_key(key_length, passphrase, &salt[0], salt.size(), @@ -224,7 +208,7 @@ direction(DECRYPTION) PBE_PKCS5v20::~PBE_PKCS5v20() { - delete hash_function; + delete m_prf; delete block_cipher; } diff --git a/src/pbe/pbes2/pbes2.h b/src/pbe/pbes2/pbes2.h index 635837b42..4c9eb9b8a 100644 --- a/src/pbe/pbes2/pbes2.h +++ b/src/pbe/pbes2/pbes2.h @@ -10,7 +10,7 @@ #include #include -#include +#include #include namespace Botan { @@ -21,12 +21,6 @@ namespace Botan { class BOTAN_DLL PBE_PKCS5v20 : public PBE { public: - /** - * @param cipher names a block cipher - * @return true iff PKCS #5 knows how to use this cipher - */ - static bool known_cipher(const std::string& cipher); - OID get_oid() const; std::vector encode_params() const; @@ -49,7 +43,7 @@ class BOTAN_DLL PBE_PKCS5v20 : public PBE * @param hash the hash function to use */ PBE_PKCS5v20(BlockCipher* cipher, - HashFunction* hash, + MessageAuthenticationCode* mac, const std::string& passphrase, std::chrono::milliseconds msec, RandomNumberGenerator& rng); @@ -60,7 +54,7 @@ class BOTAN_DLL PBE_PKCS5v20 : public PBE Cipher_Dir direction; BlockCipher* block_cipher; - HashFunction* hash_function; + MessageAuthenticationCode* m_prf; secure_vector salt, key, iv; size_t iterations, key_length; Pipe pipe; -- cgit v1.2.3