diff options
author | lloyd <[email protected]> | 2012-05-31 21:08:09 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2012-05-31 21:08:09 +0000 |
commit | 149a855bd7b090eb3868efff272e455e568eade4 (patch) | |
tree | 08df5d122f0dceb00ac4576c0714a3ab048967c7 /src | |
parent | b82642c328d98f2aaa1ac17aa0999e69e7152ae8 (diff) |
Allow arbitrary ciphers and hashes with PKCS #5 v2.0. The only
requirement is that OIDS for "<cipher>/CBC" and "HMAC(<hash>)" 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.
Diffstat (limited to 'src')
-rw-r--r-- | src/asn1/ber_dec.cpp | 3 | ||||
-rw-r--r-- | src/asn1/ber_dec.h | 2 | ||||
-rw-r--r-- | src/asn1/der_enc.cpp | 7 | ||||
-rw-r--r-- | src/asn1/der_enc.h | 1 | ||||
-rw-r--r-- | src/libstate/policy.cpp | 2 | ||||
-rw-r--r-- | src/pbe/get_pbe.cpp | 3 | ||||
-rw-r--r-- | src/pbe/pbes2/pbes2.cpp | 76 | ||||
-rw-r--r-- | src/pbe/pbes2/pbes2.h | 12 |
8 files changed, 45 insertions, 61 deletions
diff --git a/src/asn1/ber_dec.cpp b/src/asn1/ber_dec.cpp index 497f2615f..25c412600 100644 --- a/src/asn1/ber_dec.cpp +++ b/src/asn1/ber_dec.cpp @@ -221,10 +221,7 @@ BER_Object BER_Decoder::get_next_object() size_t length = decode_length(source); next.value.resize(length); if(source->read(&next.value[0], length) != length) - { - abort(); throw BER_Decoding_Error("Value truncated"); - } if(next.type_tag == EOC && next.class_tag == UNIVERSAL) return get_next_object(); diff --git a/src/asn1/ber_dec.h b/src/asn1/ber_dec.h index ee930da21..e9f519d59 100644 --- a/src/asn1/ber_dec.h +++ b/src/asn1/ber_dec.h @@ -154,7 +154,7 @@ BER_Decoder& BER_Decoder::decode_optional(T& out, if(obj.type_tag == type_tag && obj.class_tag == class_tag) { - if(class_tag & CONSTRUCTED) + if((class_tag & CONSTRUCTED) && (class_tag & CONTEXT_SPECIFIC)) BER_Decoder(obj.value).decode(out).verify_end(); else { diff --git a/src/asn1/der_enc.cpp b/src/asn1/der_enc.cpp index 594c32539..c451eae34 100644 --- a/src/asn1/der_enc.cpp +++ b/src/asn1/der_enc.cpp @@ -357,6 +357,13 @@ DER_Encoder& DER_Encoder::encode_if(bool cond, DER_Encoder& codec) return (*this); } +DER_Encoder& DER_Encoder::encode_if(bool cond, const ASN1_Object& obj) + { + if(cond) + encode(obj); + return (*this); + } + /* * Request for an object to encode itself */ diff --git a/src/asn1/der_enc.h b/src/asn1/der_enc.h index adab02247..3234445ca 100644 --- a/src/asn1/der_enc.h +++ b/src/asn1/der_enc.h @@ -91,6 +91,7 @@ class BOTAN_DLL DER_Encoder DER_Encoder& encode(const ASN1_Object& obj); DER_Encoder& encode_if(bool pred, DER_Encoder& enc); + DER_Encoder& encode_if(bool pred, const ASN1_Object& obj); DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, const byte rep[], size_t length); diff --git a/src/libstate/policy.cpp b/src/libstate/policy.cpp index 00e95d2c0..527833e61 100644 --- a/src/libstate/policy.cpp +++ b/src/libstate/policy.cpp @@ -74,7 +74,7 @@ void set_default_oids(Library_State& config) add_oid(config, "2.16.840.1.101.3.4.2.3", "SHA-512"); /* MACs */ - add_oid(config, "1.2.840.113549.2.7", "HMAC(SHA-1)"); + add_oid(config, "1.2.840.113549.2.7", "HMAC(SHA-160)"); add_oid(config, "1.2.840.113549.2.8", "HMAC(SHA-224)"); add_oid(config, "1.2.840.113549.2.9", "HMAC(SHA-256)"); add_oid(config, "1.2.840.113549.2.10", "HMAC(SHA-384)"); diff --git a/src/pbe/get_pbe.cpp b/src/pbe/get_pbe.cpp index 9ce830639..65c73eb31 100644 --- a/src/pbe/get_pbe.cpp +++ b/src/pbe/get_pbe.cpp @@ -17,6 +17,7 @@ #if defined(BOTAN_HAS_PBE_PKCS_V20) #include <botan/pbes2.h> + #include <botan/hmac.h> #endif namespace Botan { @@ -70,7 +71,7 @@ PBE* get_pbe(const std::string& algo_spec, #if defined(BOTAN_HAS_PBE_PKCS_V20) if(pbe == "PBE-PKCS5v20") return new PBE_PKCS5v20(block_cipher->clone(), - hash_function->clone(), + new HMAC(hash_function->clone()), passphrase, msec, rng); 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 <botan/pbes2.h> #include <botan/pbkdf2.h> -#include <botan/hmac.h> #include <botan/cbc.h> #include <botan/algo_factory.h> #include <botan/libstate.h> @@ -89,15 +88,17 @@ std::vector<byte> 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<byte>& 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 <botan/pbe.h> #include <botan/block_cipher.h> -#include <botan/hash.h> +#include <botan/mac.h> #include <botan/pipe.h> 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<byte> 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<byte> salt, key, iv; size_t iterations, key_length; Pipe pipe; |