aboutsummaryrefslogtreecommitdiffstats
path: root/src/pbe/pbes2/pbes2.cpp
diff options
context:
space:
mode:
authorlloyd <[email protected]>2012-05-31 21:08:09 +0000
committerlloyd <[email protected]>2012-05-31 21:08:09 +0000
commit149a855bd7b090eb3868efff272e455e568eade4 (patch)
tree08df5d122f0dceb00ac4576c0714a3ab048967c7 /src/pbe/pbes2/pbes2.cpp
parentb82642c328d98f2aaa1ac17aa0999e69e7152ae8 (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/pbe/pbes2/pbes2.cpp')
-rw-r--r--src/pbe/pbes2/pbes2.cpp76
1 files changed, 30 insertions, 46 deletions
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;
}