diff options
Diffstat (limited to 'src/lib/pbkdf')
-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 |
6 files changed, 179 insertions, 127 deletions
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 |