diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/base/info.txt | 1 | ||||
-rw-r--r-- | src/lib/ffi/ffi.cpp | 68 | ||||
-rw-r--r-- | src/lib/kdf/kdf.h | 47 | ||||
-rw-r--r-- | src/lib/kdf/kdf1/kdf1.cpp | 24 | ||||
-rw-r--r-- | src/lib/kdf/kdf1/kdf1.h | 15 | ||||
-rw-r--r-- | src/lib/kdf/kdf2/kdf2.cpp | 35 | ||||
-rw-r--r-- | src/lib/kdf/kdf2/kdf2.h | 14 | ||||
-rw-r--r-- | src/lib/kdf/prf_tls/prf_tls.cpp | 78 | ||||
-rw-r--r-- | src/lib/kdf/prf_tls/prf_tls.h | 24 | ||||
-rw-r--r-- | src/lib/kdf/prf_x942/prf_x942.cpp | 37 | ||||
-rw-r--r-- | src/lib/kdf/prf_x942/prf_x942.h | 12 | ||||
-rw-r--r-- | src/lib/passhash/bcrypt/bcrypt.cpp | 6 | ||||
-rw-r--r-- | src/lib/pbkdf/pbkdf.cpp | 55 | ||||
-rw-r--r-- | src/lib/pbkdf/pbkdf.h | 97 | ||||
-rw-r--r-- | src/lib/pbkdf/pbkdf1/pbkdf1.cpp | 30 | ||||
-rw-r--r-- | src/lib/pbkdf/pbkdf1/pbkdf1.h | 21 | ||||
-rw-r--r-- | src/lib/pbkdf/pbkdf2/pbkdf2.cpp | 84 | ||||
-rw-r--r-- | src/lib/pbkdf/pbkdf2/pbkdf2.h | 19 | ||||
-rw-r--r-- | src/lib/pubkey/dlies/dlies.cpp | 16 | ||||
-rw-r--r-- | src/tests/data/kdf/kdf1.vec | 10 |
20 files changed, 349 insertions, 344 deletions
diff --git a/src/lib/base/info.txt b/src/lib/base/info.txt index 581c40fe0..e09351596 100644 --- a/src/lib/base/info.txt +++ b/src/lib/base/info.txt @@ -23,6 +23,7 @@ hash hex mac modes +pbkdf rng stream utils diff --git a/src/lib/ffi/ffi.cpp b/src/lib/ffi/ffi.cpp index 94fc546fe..cb2efceda 100644 --- a/src/lib/ffi/ffi.cpp +++ b/src/lib/ffi/ffi.cpp @@ -128,6 +128,11 @@ int write_str_output(uint8_t out[], size_t* out_len, const std::string& str) str.size() + 1); } +int write_str_output(char out[], size_t* out_len, const std::string& str) + { + return write_str_output(reinterpret_cast<uint8_t*>(out), out_len, str); + } + #define BOTAN_FFI_DO(T, obj, block) apply_fn(obj, BOTAN_CURRENT_FUNCTION, [=](T& obj) { do { block } while(0); return 0; }) } @@ -582,15 +587,7 @@ int botan_pbkdf(const char* pbkdf_algo, uint8_t out[], size_t out_len, try { std::unique_ptr<Botan::PBKDF> pbkdf(Botan::get_pbkdf(pbkdf_algo)); - - auto r = pbkdf->derive_key(out_len, pass, salt, salt_len, iterations).bits_of(); - - if(r.size() != out_len) - throw std::runtime_error(std::string(pbkdf_algo) + " produced " + - std::to_string(r.size()) + " asked for " + - std::to_string(out_len)); - - Botan::copy_mem(out, &r[0], out_len); + pbkdf->pbkdf_iterations(out, out_len, pass, salt, salt_len, iterations); } catch(std::exception& e) { @@ -610,17 +607,9 @@ int botan_pbkdf_timed(const char* pbkdf_algo, try { std::unique_ptr<Botan::PBKDF> pbkdf(Botan::get_pbkdf(pbkdf_algo)); - - auto r = pbkdf->derive_key(out_len, password, salt, salt_len, - std::chrono::milliseconds(ms_to_run), - *iterations_used).bits_of(); - - if(r.size() != out_len) - throw std::runtime_error(std::string(pbkdf_algo) + " produced " + - std::to_string(r.size()) + " asked for " + - std::to_string(out_len)); - - Botan::copy_mem(out, &r[0], out_len); + pbkdf->pbkdf_timed(out, out_len, password, salt, salt_len, + std::chrono::milliseconds(ms_to_run), + *iterations_used); } catch(std::exception& e) { @@ -638,12 +627,7 @@ int botan_kdf(const char* kdf_algo, try { std::unique_ptr<Botan::KDF> kdf(Botan::get_kdf(kdf_algo)); - auto r = kdf->derive_key(out_len, secret, secret_len, salt, salt_len); - if(r.size() != out_len) - throw std::runtime_error(std::string(kdf_algo) + " produced " + - std::to_string(r.size()) + " asked for " + - std::to_string(out_len)); - Botan::copy_mem(out, &r[0], out_len); + kdf->kdf(out, out_len, secret, secret_len, salt, salt_len); } catch(std::exception& e) { @@ -860,20 +844,7 @@ int botan_privkey_export_pubkey(botan_pubkey_t* pubout, botan_privkey_t key_obj) int botan_pubkey_algo_name(botan_pubkey_t key, char out[], size_t* out_len) { - return apply_fn(key, BOTAN_CURRENT_FUNCTION, - [out,out_len](Botan::Public_Key& k) - { - const std::string name = k.algo_name(); - const size_t avail = *out_len; - *out_len = name.size() + 1; - if(avail > 1 + name.size()) - { - Botan::copy_mem(out, name.data(), name.size()); - out[name.size()] = 0; - return 0; - } - return -1; - }); + return BOTAN_FFI_DO(Botan::Public_Key, key, { return write_str_output(out, out_len, key.algo_name()); }); } int botan_pubkey_export(botan_pubkey_t key, uint8_t out[], size_t* out_len, uint32_t flags) @@ -1147,20 +1118,9 @@ int botan_pk_op_key_agreement_export_public(botan_privkey_t key, uint8_t out[], size_t* out_len) { return BOTAN_FFI_DO(Botan::Private_Key, key, { - auto kak = dynamic_cast<const Botan::PK_Key_Agreement_Key*>(&key); - if(!kak) - return -2; - const std::vector<uint8_t> pv = kak->public_value(); - const size_t avail = *out_len; - *out_len = pv.size(); - - if(pv.size() <= avail) - { - Botan::copy_mem(out, &pv[0], pv.size()); - return 0; - } - - return -1; + if(auto kak = dynamic_cast<const Botan::PK_Key_Agreement_Key*>(&key)) + return write_vec_output(out, out_len, kak->public_value()); + return -2; }); } diff --git a/src/lib/kdf/kdf.h b/src/lib/kdf/kdf.h index 9d8ca57fc..dc23a82bd 100644 --- a/src/lib/kdf/kdf.h +++ b/src/lib/kdf/kdf.h @@ -25,6 +25,30 @@ class BOTAN_DLL KDF virtual std::string name() const = 0; + virtual size_t kdf(byte key[], size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const = 0; + + + /** + * Derive a key + * @param key_len the desired output length in bytes + * @param secret the secret input + * @param secret_len size of secret in bytes + * @param salt a diversifier + * @param salt_len size of salt in bytes + */ + secure_vector<byte> derive_key(size_t key_len, + const byte secret[], + size_t secret_len, + const byte salt[], + size_t salt_len) const + { + secure_vector<byte> key(key_len); + key.resize(kdf(&key[0], key.size(), secret, secret_len, salt, salt_len)); + return key; + } + /** * Derive a key * @param key_len the desired output length in bytes @@ -90,31 +114,10 @@ class BOTAN_DLL KDF salt.length()); } - /** - * Derive a key - * @param key_len the desired output length in bytes - * @param secret the secret input - * @param secret_len size of secret in bytes - * @param salt a diversifier - * @param salt_len size of salt in bytes - */ - secure_vector<byte> derive_key(size_t key_len, - const byte secret[], - size_t secret_len, - const byte salt[], - size_t salt_len) const - { - return derive(key_len, secret, secret_len, salt, salt_len); - } - virtual KDF* clone() const = 0; typedef SCAN_Name Spec; - private: - virtual secure_vector<byte> - derive(size_t key_len, - const byte secret[], size_t secret_len, - const byte salt[], size_t salt_len) const = 0; + }; /** diff --git a/src/lib/kdf/kdf1/kdf1.cpp b/src/lib/kdf/kdf1/kdf1.cpp index df84a1a00..c2a74027b 100644 --- a/src/lib/kdf/kdf1/kdf1.cpp +++ b/src/lib/kdf/kdf1/kdf1.cpp @@ -12,16 +12,22 @@ namespace Botan { BOTAN_REGISTER_KDF_1HASH(KDF1, "KDF1"); -/* -* KDF1 Key Derivation Mechanism -*/ -secure_vector<byte> KDF1::derive(size_t, - const byte secret[], size_t secret_len, - const byte P[], size_t P_len) const +size_t KDF1::kdf(byte key[], size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const { - hash->update(secret, secret_len); - hash->update(P, P_len); - return hash->final(); + m_hash->update(secret, secret_len); + m_hash->update(salt, salt_len); + + if(key_len < m_hash->output_length()) + { + secure_vector<byte> v = m_hash->final(); + copy_mem(key, &v[0], key_len); + return key_len; + } + + m_hash->final(key); + return m_hash->output_length(); } } diff --git a/src/lib/kdf/kdf1/kdf1.h b/src/lib/kdf/kdf1/kdf1.h index 9f617878b..a22d19d97 100644 --- a/src/lib/kdf/kdf1/kdf1.h +++ b/src/lib/kdf/kdf1/kdf1.h @@ -19,16 +19,17 @@ namespace Botan { class BOTAN_DLL KDF1 : public KDF { public: - secure_vector<byte> derive(size_t, - const byte secret[], size_t secret_len, - const byte P[], size_t P_len) const; + std::string name() const override { return "KDF1(" + m_hash->name() + ")"; } - std::string name() const { return "KDF1(" + hash->name() + ")"; } - KDF* clone() const { return new KDF1(hash->clone()); } + KDF* clone() const override { return new KDF1(m_hash->clone()); } - KDF1(HashFunction* h) : hash(h) {} + size_t kdf(byte key[], size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const override; + + KDF1(HashFunction* h) : m_hash(h) {} private: - std::unique_ptr<HashFunction> hash; + std::unique_ptr<HashFunction> m_hash; }; } diff --git a/src/lib/kdf/kdf2/kdf2.cpp b/src/lib/kdf/kdf2/kdf2.cpp index c7b355580..f1a702887 100644 --- a/src/lib/kdf/kdf2/kdf2.cpp +++ b/src/lib/kdf/kdf2/kdf2.cpp @@ -12,32 +12,27 @@ namespace Botan { BOTAN_REGISTER_KDF_1HASH(KDF2, "KDF2"); -/* -* KDF2 Key Derivation Mechanism -*/ -secure_vector<byte> KDF2::derive(size_t out_len, - const byte secret[], size_t secret_len, - const byte P[], size_t P_len) const +size_t KDF2::kdf(byte key[], size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const { - secure_vector<byte> output; u32bit counter = 1; + secure_vector<byte> h; - while(out_len && counter) + size_t offset = 0; + while(offset != key_len && counter != 0) { - hash->update(secret, secret_len); - hash->update_be(counter); - hash->update(P, P_len); - - secure_vector<byte> hash_result = hash->final(); - - size_t added = std::min(hash_result.size(), out_len); - output += std::make_pair(&hash_result[0], added); - out_len -= added; - - ++counter; + m_hash->update(secret, secret_len); + m_hash->update_be(counter++); + m_hash->update(salt, salt_len); + m_hash->final(h); + + const size_t added = std::min(h.size(), key_len - offset); + copy_mem(&key[offset], &h[0], added); + offset += added; } - return output; + return offset; } } diff --git a/src/lib/kdf/kdf2/kdf2.h b/src/lib/kdf/kdf2/kdf2.h index c574336b6..e8a8be1fa 100644 --- a/src/lib/kdf/kdf2/kdf2.h +++ b/src/lib/kdf/kdf2/kdf2.h @@ -19,15 +19,17 @@ namespace Botan { class BOTAN_DLL KDF2 : public KDF { public: - secure_vector<byte> derive(size_t, const byte[], size_t, - const byte[], size_t) const; + std::string name() const override { return "KDF2(" + m_hash->name() + ")"; } - std::string name() const { return "KDF2(" + hash->name() + ")"; } - KDF* clone() const { return new KDF2(hash->clone()); } + KDF* clone() const override { return new KDF2(m_hash->clone()); } - KDF2(HashFunction* h) : hash(h) {} + size_t kdf(byte key[], size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const override; + + KDF2(HashFunction* h) : m_hash(h) {} private: - std::unique_ptr<HashFunction> hash; + std::unique_ptr<HashFunction> m_hash; }; } diff --git a/src/lib/kdf/prf_tls/prf_tls.cpp b/src/lib/kdf/prf_tls/prf_tls.cpp index f1061fd10..9161dc71e 100644 --- a/src/lib/kdf/prf_tls/prf_tls.cpp +++ b/src/lib/kdf/prf_tls/prf_tls.cpp @@ -23,15 +23,21 @@ TLS_12_PRF* TLS_12_PRF::make(const Spec& spec) BOTAN_REGISTER_NAMED_T(KDF, "TLS-12-PRF", TLS_12_PRF, TLS_12_PRF::make); BOTAN_REGISTER_KDF_NOARGS(TLS_PRF, "TLS-PRF"); +TLS_PRF::TLS_PRF() + { + m_hmac_md5.reset(make_a<MessageAuthenticationCode>("HMAC(MD5)")); + m_hmac_sha1.reset(make_a<MessageAuthenticationCode>("HMAC(SHA-1)")); + } + namespace { /* * TLS PRF P_hash function */ -void P_hash(secure_vector<byte>& output, +void P_hash(byte out[], size_t out_len, MessageAuthenticationCode& mac, const byte secret[], size_t secret_len, - const byte seed[], size_t seed_len) + const byte salt[], size_t salt_len) { try { @@ -44,73 +50,47 @@ void P_hash(secure_vector<byte>& output, " bytes is too long for the PRF"); } - secure_vector<byte> A(seed, seed + seed_len); + secure_vector<byte> A(salt, salt + salt_len); + secure_vector<byte> h; size_t offset = 0; - while(offset != output.size()) + while(offset != out_len) { - const size_t this_block_len = - std::min<size_t>(mac.output_length(), output.size() - offset); - A = mac.process(A); mac.update(A); - mac.update(seed, seed_len); - secure_vector<byte> block = mac.final(); + mac.update(salt, salt_len); + mac.final(h); - xor_buf(&output[offset], &block[0], this_block_len); - offset += this_block_len; + const size_t writing = std::min(h.size(), out_len - offset); + xor_buf(&out[offset], &h[0], writing); + offset += writing; } } } -/* -* TLS PRF Constructor and Destructor -*/ -TLS_PRF::TLS_PRF() - { - hmac_md5.reset(make_a<MessageAuthenticationCode>("HMAC(MD5)")); - hmac_sha1.reset(make_a<MessageAuthenticationCode>("HMAC(SHA-1)")); - } - -/* -* TLS PRF -*/ -secure_vector<byte> TLS_PRF::derive(size_t key_len, - const byte secret[], size_t secret_len, - const byte seed[], size_t seed_len) const +size_t TLS_PRF::kdf(byte key[], size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const { - secure_vector<byte> output(key_len); - - size_t S1_len = (secret_len + 1) / 2, - S2_len = (secret_len + 1) / 2; + const size_t S1_len = (secret_len + 1) / 2, + S2_len = (secret_len + 1) / 2; const byte* S1 = secret; const byte* S2 = secret + (secret_len - S2_len); - P_hash(output, *hmac_md5, S1, S1_len, seed, seed_len); - P_hash(output, *hmac_sha1, S2, S2_len, seed, seed_len); - - return output; + P_hash(key, key_len, *m_hmac_md5, S1, S1_len, salt, salt_len); + P_hash(key, key_len, *m_hmac_sha1, S2, S2_len, salt, salt_len); + return key_len; } -/* -* TLS v1.2 PRF Constructor and Destructor -*/ -TLS_12_PRF::TLS_12_PRF(MessageAuthenticationCode* mac) : m_mac(mac) +size_t TLS_12_PRF::kdf(byte key[], size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const { - } - -secure_vector<byte> TLS_12_PRF::derive(size_t key_len, - const byte secret[], size_t secret_len, - const byte seed[], size_t seed_len) const - { - secure_vector<byte> output(key_len); - - P_hash(output, *m_mac, secret, secret_len, seed, seed_len); - - return output; + P_hash(key, key_len, *m_mac, secret, secret_len, salt, salt_len); + return key_len; } } diff --git a/src/lib/kdf/prf_tls/prf_tls.h b/src/lib/kdf/prf_tls/prf_tls.h index c3adc6caf..e2289a6e8 100644 --- a/src/lib/kdf/prf_tls/prf_tls.h +++ b/src/lib/kdf/prf_tls/prf_tls.h @@ -19,17 +19,18 @@ namespace Botan { class BOTAN_DLL TLS_PRF : public KDF { public: - secure_vector<byte> derive(size_t key_len, - const byte secret[], size_t secret_len, - const byte seed[], size_t seed_len) const; - std::string name() const { return "TLS-PRF"; } + KDF* clone() const { return new TLS_PRF; } + size_t kdf(byte key[], size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const override; + TLS_PRF(); private: - std::unique_ptr<MessageAuthenticationCode> hmac_md5; - std::unique_ptr<MessageAuthenticationCode> hmac_sha1; + std::unique_ptr<MessageAuthenticationCode> m_hmac_md5; + std::unique_ptr<MessageAuthenticationCode> m_hmac_sha1; }; /** @@ -38,14 +39,15 @@ class BOTAN_DLL TLS_PRF : public KDF class BOTAN_DLL TLS_12_PRF : public KDF { public: - secure_vector<byte> derive(size_t key_len, - const byte secret[], size_t secret_len, - const byte seed[], size_t seed_len) const; - std::string name() const { return "TLS-12-PRF(" + m_mac->name() + ")"; } + KDF* clone() const { return new TLS_12_PRF(m_mac->clone()); } - TLS_12_PRF(MessageAuthenticationCode* mac); + size_t kdf(byte key[], size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const override; + + TLS_12_PRF(MessageAuthenticationCode* mac) : m_mac(mac) {} static TLS_12_PRF* make(const Spec& spec); private: diff --git a/src/lib/kdf/prf_x942/prf_x942.cpp b/src/lib/kdf/prf_x942/prf_x942.cpp index 30bf737a9..5ca0f01ff 100644 --- a/src/lib/kdf/prf_x942/prf_x942.cpp +++ b/src/lib/kdf/prf_x942/prf_x942.cpp @@ -9,7 +9,7 @@ #include <botan/prf_x942.h> #include <botan/der_enc.h> #include <botan/oids.h> -#include <botan/sha160.h> +#include <botan/hash.h> #include <botan/loadstor.h> #include <algorithm> @@ -31,24 +31,22 @@ std::vector<byte> encode_x942_int(u32bit n) } -/* -* X9.42 PRF -*/ -secure_vector<byte> X942_PRF::derive(size_t key_len, - const byte secret[], size_t secret_len, - const byte salt[], size_t salt_len) const +size_t X942_PRF::kdf(byte key[], size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const { - SHA_160 hash; - const OID kek_algo(key_wrap_oid); + std::unique_ptr<HashFunction> hash(make_a<HashFunction>("SHA-160")); + const OID kek_algo(m_key_wrap_oid); - secure_vector<byte> key; + secure_vector<byte> h; + size_t offset = 0; u32bit counter = 1; - while(key.size() != key_len && counter) + while(offset != key_len && counter) { - hash.update(secret, secret_len); + hash->update(secret, secret_len); - hash.update( + hash->update( DER_Encoder().start_cons(SEQUENCE) .start_cons(SEQUENCE) @@ -70,14 +68,15 @@ secure_vector<byte> X942_PRF::derive(size_t key_len, .end_cons().get_contents() ); - secure_vector<byte> digest = hash.final(); - const size_t needed = std::min(digest.size(), key_len - key.size()); - key += std::make_pair(&digest[0], needed); + hash->final(h); + const size_t copied = std::min(h.size(), key_len - offset); + copy_mem(&key[offset], &h[0], copied); + offset += copied; ++counter; } - return key; + return offset; } /* @@ -86,9 +85,9 @@ secure_vector<byte> X942_PRF::derive(size_t key_len, X942_PRF::X942_PRF(const std::string& oid) { if(OIDS::have_oid(oid)) - key_wrap_oid = OIDS::lookup(oid).as_string(); + m_key_wrap_oid = OIDS::lookup(oid).as_string(); else - key_wrap_oid = oid; + m_key_wrap_oid = oid; } } diff --git a/src/lib/kdf/prf_x942/prf_x942.h b/src/lib/kdf/prf_x942/prf_x942.h index d2678c127..242a83150 100644 --- a/src/lib/kdf/prf_x942/prf_x942.h +++ b/src/lib/kdf/prf_x942/prf_x942.h @@ -18,15 +18,17 @@ namespace Botan { class BOTAN_DLL X942_PRF : public KDF { public: - secure_vector<byte> derive(size_t, const byte[], size_t, - const byte[], size_t) const; + std::string name() const { return "X942_PRF(" + m_key_wrap_oid + ")"; } - std::string name() const { return "X942_PRF(" + key_wrap_oid + ")"; } - KDF* clone() const { return new X942_PRF(key_wrap_oid); } + KDF* clone() const { return new X942_PRF(m_key_wrap_oid); } + + size_t kdf(byte key[], size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const override; X942_PRF(const std::string& oid); private: - std::string key_wrap_oid; + std::string m_key_wrap_oid; }; } diff --git a/src/lib/passhash/bcrypt/bcrypt.cpp b/src/lib/passhash/bcrypt/bcrypt.cpp index 6766dc0d1..218404110 100644 --- a/src/lib/passhash/bcrypt/bcrypt.cpp +++ b/src/lib/passhash/bcrypt/bcrypt.cpp @@ -140,11 +140,13 @@ bool check_bcrypt(const std::string& pass, const std::string& hash) const u16bit workfactor = to_u32bit(hash.substr(4, 2)); - std::vector<byte> salt = bcrypt_base64_decode(hash.substr(7, 22)); + const std::vector<byte> salt = bcrypt_base64_decode(hash.substr(7, 22)); + if(salt.size() != 16) + return false; const std::string compare = make_bcrypt(pass, salt, workfactor); - return (hash == compare); + return same_mem(hash.data(), compare.data(), compare.size()); } } diff --git a/src/lib/pbkdf/pbkdf.cpp b/src/lib/pbkdf/pbkdf.cpp index 973805f65..6fbf8ba37 100644 --- a/src/lib/pbkdf/pbkdf.cpp +++ b/src/lib/pbkdf/pbkdf.cpp @@ -10,35 +10,48 @@ namespace Botan { -OctetString PBKDF::derive_key(size_t output_len, - const std::string& passphrase, - const byte salt[], size_t salt_len, - size_t iterations) const +void PBKDF::pbkdf_timed(byte out[], size_t out_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + std::chrono::milliseconds msec, + size_t& iterations) const + { + iterations = pbkdf(out, out_len, passphrase, salt, salt_len, 0, msec); + } + +void PBKDF::pbkdf_iterations(byte out[], size_t out_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + size_t iterations) const { if(iterations == 0) throw std::invalid_argument(name() + ": Invalid iteration count"); - auto derived = key_derivation(output_len, passphrase, - salt, salt_len, iterations, - std::chrono::milliseconds(0)); - - BOTAN_ASSERT(derived.first == iterations, - "PBKDF used the correct number of iterations"); - - return derived.second; + const size_t iterations_run = pbkdf(out, out_len, passphrase, + salt, salt_len, iterations, + std::chrono::milliseconds(0)); + BOTAN_ASSERT_EQUAL(iterations, iterations_run, "Expected PBKDF iterations"); } -OctetString PBKDF::derive_key(size_t output_len, - const std::string& passphrase, - const byte salt[], size_t salt_len, - std::chrono::milliseconds ms, - size_t& iterations) const +secure_vector<byte> PBKDF::pbkdf_iterations(size_t out_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + size_t iterations) const { - auto derived = key_derivation(output_len, passphrase, salt, salt_len, 0, ms); - - iterations = derived.first; + secure_vector<byte> out(out_len); + pbkdf_iterations(&out[0], out_len, passphrase, salt, salt_len, iterations); + return out; + } - return derived.second; +secure_vector<byte> PBKDF::pbkdf_timed(size_t out_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + std::chrono::milliseconds msec, + size_t& iterations) const + { + secure_vector<byte> out(out_len); + pbkdf_timed(&out[0], out_len, passphrase, salt, salt_len, msec, iterations); + return out; } } diff --git a/src/lib/pbkdf/pbkdf.h b/src/lib/pbkdf/pbkdf.h index ad5346e36..3eaa293a1 100644 --- a/src/lib/pbkdf/pbkdf.h +++ b/src/lib/pbkdf/pbkdf.h @@ -1,6 +1,6 @@ /* * PBKDF -* (C) 1999-2007,2012 Jack Lloyd +* (C) 1999-2007,2012,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -35,87 +35,116 @@ class BOTAN_DLL PBKDF virtual std::string name() const = 0; /** + * 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 out_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) + * @param msec if iterations is zero, then instead the PBKDF is + * run until msec milliseconds has passed. + * @return the number of iterations performed + */ + virtual size_t pbkdf(byte out[], size_t out_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec) const = 0; + + void pbkdf_iterations(byte out[], size_t out_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + size_t iterations) const; + + void pbkdf_timed(byte out[], size_t out_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + std::chrono::milliseconds msec, + size_t& iterations) const; + + secure_vector<byte> pbkdf_iterations(size_t out_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + size_t iterations) const; + + secure_vector<byte> pbkdf_timed(size_t out_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + std::chrono::milliseconds msec, + size_t& iterations) const; + + // Following kept for compat with 1.10: + + /** * Derive a key from a passphrase - * @param output_len the desired length of the key to produce + * @param out_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) */ - OctetString derive_key(size_t output_len, + OctetString derive_key(size_t out_len, const std::string& passphrase, const byte salt[], size_t salt_len, - size_t iterations) const; + size_t iterations) const + { + return pbkdf_iterations(out_len, passphrase, salt, salt_len, iterations); + } /** * Derive a key from a passphrase - * @param output_len the desired length of the key to produce + * @param out_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 iterations the number of iterations to use (use 10K or more) */ template<typename Alloc> - OctetString derive_key(size_t output_len, + OctetString derive_key(size_t out_len, const std::string& passphrase, const std::vector<byte, Alloc>& salt, size_t iterations) const { - return derive_key(output_len, passphrase, &salt[0], salt.size(), iterations); + return pbkdf_iterations(out_len, passphrase, &salt[0], salt.size(), iterations); } /** * Derive a key from a passphrase - * @param output_len the desired length of the key to produce + * @param out_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, + OctetString derive_key(size_t out_len, const std::string& passphrase, const byte salt[], size_t salt_len, std::chrono::milliseconds msec, - size_t& iterations) const; + size_t& iterations) const + { + return pbkdf_timed(out_len, passphrase, salt, salt_len, msec, iterations); + } /** * Derive a key from a passphrase using a certain amount of time - * @param output_len the desired length of the key to produce + * @param out_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 msec is how long to run the PBKDF * @param iterations is set to the number of iterations used */ template<typename Alloc> - OctetString derive_key(size_t output_len, + OctetString derive_key(size_t out_len, const std::string& passphrase, const std::vector<byte, Alloc>& salt, std::chrono::milliseconds msec, size_t& iterations) const { - return derive_key(output_len, passphrase, &salt[0], salt.size(), msec, iterations); + return pbkdf_timed(out_len, passphrase, &salt[0], salt.size(), msec, iterations); } - - /** - * 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) - * @param msec if iterations is zero, then instead the PBKDF is - * run until msec milliseconds has passed. - * @return the number of iterations performed and the derived key - */ - 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/lib/pbkdf/pbkdf1/pbkdf1.cpp b/src/lib/pbkdf/pbkdf1/pbkdf1.cpp index e5dda579f..8134b39c4 100644 --- a/src/lib/pbkdf/pbkdf1/pbkdf1.cpp +++ b/src/lib/pbkdf/pbkdf1/pbkdf1.cpp @@ -13,22 +13,18 @@ namespace Botan { BOTAN_REGISTER_PBKDF_1HASH(PKCS5_PBKDF1, "PBKDF1") -/* -* Return a PKCS#5 PBKDF1 derived key -*/ -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 +size_t PKCS5_PBKDF1::pbkdf(byte output_buf[], size_t output_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec) const { - if(key_len > hash->output_length()) + if(output_len > m_hash->output_length()) throw Invalid_Argument("PKCS5_PBKDF1: Requested output length too long"); - hash->update(passphrase); - hash->update(salt, salt_len); - secure_vector<byte> key = hash->final(); + m_hash->update(passphrase); + m_hash->update(salt, salt_len); + secure_vector<byte> key = m_hash->final(); const auto start = std::chrono::high_resolution_clock::now(); size_t iterations_performed = 1; @@ -48,14 +44,14 @@ PKCS5_PBKDF1::key_derivation(size_t key_len, else if(iterations_performed == iterations) break; - hash->update(key); - hash->final(&key[0]); + m_hash->update(key); + m_hash->final(&key[0]); ++iterations_performed; } - return std::make_pair(iterations_performed, - OctetString(&key[0], std::min(key_len, key.size()))); + copy_mem(output_buf, &key[0], output_len); + return iterations_performed; } } diff --git a/src/lib/pbkdf/pbkdf1/pbkdf1.h b/src/lib/pbkdf/pbkdf1/pbkdf1.h index 4c2f3888c..c93dbe503 100644 --- a/src/lib/pbkdf/pbkdf1/pbkdf1.h +++ b/src/lib/pbkdf/pbkdf1/pbkdf1.h @@ -23,28 +23,27 @@ class BOTAN_DLL PKCS5_PBKDF1 : public PBKDF public: /** * Create a PKCS #5 instance using the specified hash function. - * @param hash_in pointer to a hash function object to use + * @param hash pointer to a hash function object to use */ - PKCS5_PBKDF1(HashFunction* hash_in) : hash(hash_in) {} + PKCS5_PBKDF1(HashFunction* hash) : m_hash(hash) {} std::string name() const { - return "PBKDF1(" + hash->name() + ")"; + return "PBKDF1(" + m_hash->name() + ")"; } PBKDF* clone() const { - return new PKCS5_PBKDF1(hash->clone()); + return new PKCS5_PBKDF1(m_hash->clone()); } - 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; + size_t pbkdf(byte output_buf[], 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: - std::unique_ptr<HashFunction> hash; + std::unique_ptr<HashFunction> m_hash; }; } diff --git a/src/lib/pbkdf/pbkdf2/pbkdf2.cpp b/src/lib/pbkdf/pbkdf2/pbkdf2.cpp index 146dd15b0..0ff412bc5 100644 --- a/src/lib/pbkdf/pbkdf2/pbkdf2.cpp +++ b/src/lib/pbkdf/pbkdf2/pbkdf2.cpp @@ -27,51 +27,49 @@ PKCS5_PBKDF2* PKCS5_PBKDF2::make(const Spec& spec) return nullptr; } -/* -* Return a PKCS #5 PBKDF2 derived key -*/ -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 +size_t +pbkdf2(MessageAuthenticationCode& prf, + byte out[], + size_t out_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec) { - if(key_len == 0) - return std::make_pair(iterations, OctetString()); + clear_mem(out, out_len); + + if(out_len == 0) + return 0; try { - mac->set_key(reinterpret_cast<const byte*>(passphrase.data()), - passphrase.length()); + prf.set_key(reinterpret_cast<const byte*>(passphrase.data()), passphrase.size()); } catch(Invalid_Key_Length) { - throw Exception(name() + " cannot accept passphrases of length " + - std::to_string(passphrase.length())); + throw std::runtime_error("PBKDF2 with " + prf.name() + + " cannot accept passphrases of length " + + std::to_string(passphrase.size())); } - secure_vector<byte> key(key_len); - - byte* T = &key[0]; - - secure_vector<byte> U(mac->output_length()); + const size_t prf_sz = prf.output_length(); + secure_vector<byte> U(prf_sz); - const size_t blocks_needed = round_up(key_len, mac->output_length()) / mac->output_length(); + const size_t blocks_needed = round_up(out_len, prf_sz) / prf_sz; std::chrono::microseconds usec_per_block = std::chrono::duration_cast<std::chrono::microseconds>(msec) / blocks_needed; u32bit counter = 1; - while(key_len) + while(out_len) { - size_t T_size = std::min<size_t>(mac->output_length(), key_len); + const size_t prf_output = std::min<size_t>(prf_sz, out_len); - mac->update(salt, salt_len); - mac->update_be(counter); - mac->final(&U[0]); + prf.update(salt, salt_len); + prf.update_be(counter++); + prf.final(&U[0]); - xor_buf(T, &U[0], T_size); + xor_buf(out, &U[0], prf_output); if(iterations == 0) { @@ -86,9 +84,9 @@ PKCS5_PBKDF2::key_derivation(size_t key_len, while(true) { - mac->update(U); - mac->final(&U[0]); - xor_buf(T, &U[0], T_size); + prf.update(U); + prf.final(&U[0]); + xor_buf(out, &U[0], prf_output); iterations++; /* @@ -96,7 +94,7 @@ PKCS5_PBKDF2::key_derivation(size_t key_len, avoids confusion, and likely some broken implementations break on getting completely randomly distributed values */ - if(iterations % 1000 == 0) + if(iterations % 10000 == 0) { auto time_taken = std::chrono::high_resolution_clock::now() - start; auto usec_taken = std::chrono::duration_cast<std::chrono::microseconds>(time_taken); @@ -109,18 +107,28 @@ PKCS5_PBKDF2::key_derivation(size_t key_len, { for(size_t i = 1; i != iterations; ++i) { - mac->update(U); - mac->final(&U[0]); - xor_buf(T, &U[0], T_size); + prf.update(U); + prf.final(&U[0]); + xor_buf(out, &U[0], prf_output); } } - key_len -= T_size; - T += T_size; - ++counter; + out_len -= prf_output; + out += prf_output; } - return std::make_pair(iterations, key); + return iterations; } +size_t +PKCS5_PBKDF2::pbkdf(byte key[], size_t key_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec) const + { + return pbkdf2(*mac.get(), key, key_len, passphrase, salt, salt_len, iterations, msec); + } + + } diff --git a/src/lib/pbkdf/pbkdf2/pbkdf2.h b/src/lib/pbkdf/pbkdf2/pbkdf2.h index 3d1a14fab..d74410b89 100644 --- a/src/lib/pbkdf/pbkdf2/pbkdf2.h +++ b/src/lib/pbkdf/pbkdf2/pbkdf2.h @@ -14,6 +14,14 @@ namespace Botan { +BOTAN_DLL size_t pbkdf2(MessageAuthenticationCode& prf, + byte out[], + size_t out_len, + const std::string& passphrase, + const byte salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec); + /** * PKCS #5 PBKDF2 */ @@ -30,12 +38,11 @@ class BOTAN_DLL PKCS5_PBKDF2 : public PBKDF return new PKCS5_PBKDF2(mac->clone()); } - 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; + size_t pbkdf(byte output_buf[], 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/lib/pubkey/dlies/dlies.cpp b/src/lib/pubkey/dlies/dlies.cpp index 42ecfb561..899ee98aa 100644 --- a/src/lib/pubkey/dlies/dlies.cpp +++ b/src/lib/pubkey/dlies/dlies.cpp @@ -44,14 +44,14 @@ std::vector<byte> DLIES_Encryptor::enc(const byte in[], size_t length, vz += ka.derive_key(0, other_key).bits_of(); const size_t K_LENGTH = length + mac_keylen; - OctetString K = kdf->derive_key(K_LENGTH, vz); + secure_vector<byte> K = kdf->derive_key(K_LENGTH, vz); - if(K.length() != K_LENGTH) + if(K.size() != K_LENGTH) throw Encoding_Error("DLIES: KDF did not provide sufficient output"); byte* C = &out[my_key.size()]; - xor_buf(C, K.begin() + mac_keylen, length); - mac->set_key(K.begin(), mac_keylen); + mac->set_key(&K[0], mac_keylen); + xor_buf(C, &K[mac_keylen], length); mac->update(C, length); for(size_t j = 0; j != 8; ++j) @@ -114,11 +114,11 @@ secure_vector<byte> DLIES_Decryptor::dec(const byte msg[], size_t length) const vz += ka.derive_key(0, v).bits_of(); const size_t K_LENGTH = C.size() + mac_keylen; - OctetString K = kdf->derive_key(K_LENGTH, vz); - if(K.length() != K_LENGTH) + secure_vector<byte> K = kdf->derive_key(K_LENGTH, vz); + if(K.size() != K_LENGTH) throw Encoding_Error("DLIES: KDF did not provide sufficient output"); - mac->set_key(K.begin(), mac_keylen); + mac->set_key(&K[0], mac_keylen); mac->update(C); for(size_t j = 0; j != 8; ++j) mac->update(0); @@ -126,7 +126,7 @@ secure_vector<byte> DLIES_Decryptor::dec(const byte msg[], size_t length) const if(T != T2) throw Decoding_Error("DLIES: message authentication failed"); - xor_buf(C, K.begin() + mac_keylen, C.size()); + xor_buf(C, &K[0] + mac_keylen, C.size()); return C; } diff --git a/src/tests/data/kdf/kdf1.vec b/src/tests/data/kdf/kdf1.vec index 14f605e5d..990fcf970 100644 --- a/src/tests/data/kdf/kdf1.vec +++ b/src/tests/data/kdf/kdf1.vec @@ -1,26 +1,26 @@ [KDF1(SHA-1)] Secret = 61736F67696A6F7367696A736F69676A736F6964676A6F696A6F736467696A736F6964676A736F6964676A736F696A Salt = -OutputLen = 0 +OutputLen = 20 Output = A0D760447F105CE64DB99FF2FC92F961F24E7D9C Secret = 61736F67696A6F7367696A736F69676A736F6964676A6F696A6F736467696A73 Salt = 6F6964676A736F6964676A736F696A -OutputLen = 0 +OutputLen = 20 Output = A0D760447F105CE64DB99FF2FC92F961F24E7D9C Secret = 61736F67696A6F7367696A736F69676A736F6964676A6F696A6F736467696A Salt = 736F6964676A736F6964676A736F696A -OutputLen = 0 +OutputLen = 20 Output = A0D760447F105CE64DB99FF2FC92F961F24E7D9C Secret = 617361736F67696A6F7367696A736F69676A736F6964676A6F696A6F736467696A736F6964676A736F6964676A736F696A0A Salt = -OutputLen = 0 +OutputLen = 20 Output = DBFEFA0EA12D352C4AE5B0AF17D061E0E2C469A8 Secret = 617361736F67696A6F7367696A736F69676A736F6964676A6F696A6F73646769 Salt = 6A736F6964676A736F6964676A736F696A0A -OutputLen = 0 +OutputLen = 20 Output = DBFEFA0EA12D352C4AE5B0AF17D061E0E2C469A8 |