diff options
-rw-r--r-- | doc/api_ref/pbkdf.rst | 10 | ||||
-rw-r--r-- | src/lib/pbkdf/argon2/argon2.h | 6 | ||||
-rw-r--r-- | src/lib/pbkdf/argon2/argon2pwhash.cpp | 14 | ||||
-rw-r--r-- | src/lib/pbkdf/pwdhash.cpp | 16 | ||||
-rw-r--r-- | src/lib/pbkdf/pwdhash.h | 26 | ||||
-rw-r--r-- | src/tests/test_pbkdf.cpp | 44 |
6 files changed, 81 insertions, 35 deletions
diff --git a/doc/api_ref/pbkdf.rst b/doc/api_ref/pbkdf.rst index 137ad2d3c..5e3b5f4bd 100644 --- a/doc/api_ref/pbkdf.rst +++ b/doc/api_ref/pbkdf.rst @@ -28,6 +28,16 @@ specified with all parameters (say "Scrypt" with ``N`` = 8192, ``r`` = 64, and Derive a key from the specified password and salt, placing it into output. + .. cpp:function:: void derive_key(uint8_t out[], size_t out_len, \ + const char* password, const size_t password_len, \ + const uint8_t salt[], size_t salt_len, \ + const uint8_t ad[], size_t ad_len, \ + const uint8_t key[], size_t key_len) const + + Derive a key from the specified password, salt, associated data, and + secret key, placing it into output. The ad and key are both allowed + to be empty. Currently non-empty AD/key is only supported with Argon2. + .. cpp:function:: std::string to_string() const Return a descriptive string including the parameters (iteration count, etc) diff --git a/src/lib/pbkdf/argon2/argon2.h b/src/lib/pbkdf/argon2/argon2.h index 82880031a..44447360b 100644 --- a/src/lib/pbkdf/argon2/argon2.h +++ b/src/lib/pbkdf/argon2/argon2.h @@ -37,6 +37,12 @@ class BOTAN_PUBLIC_API(2,11) Argon2 final : public PasswordHash const char* password, size_t password_len, const uint8_t salt[], size_t salt_len) const override; + void derive_key(uint8_t out[], size_t out_len, + const char* password, size_t password_len, + const uint8_t salt[], size_t salt_len, + const uint8_t ad[], size_t ad_len, + const uint8_t key[], size_t key_len) const override; + std::string to_string() const override; size_t M() const { return m_M; } diff --git a/src/lib/pbkdf/argon2/argon2pwhash.cpp b/src/lib/pbkdf/argon2/argon2pwhash.cpp index 6df23127c..a9d1994c3 100644 --- a/src/lib/pbkdf/argon2/argon2pwhash.cpp +++ b/src/lib/pbkdf/argon2/argon2pwhash.cpp @@ -30,6 +30,20 @@ void Argon2::derive_key(uint8_t output[], size_t output_len, m_family, m_p, m_M, m_t); } +void Argon2::derive_key(uint8_t output[], size_t output_len, + const char* password, size_t password_len, + const uint8_t salt[], size_t salt_len, + const uint8_t ad[], size_t ad_len, + const uint8_t key[], size_t key_len) const + { + argon2(output, output_len, + password, password_len, + salt, salt_len, + key, key_len, + ad, ad_len, + m_family, m_p, m_M, m_t); + } + namespace { std::string argon2_family_name(uint8_t f) diff --git a/src/lib/pbkdf/pwdhash.cpp b/src/lib/pbkdf/pwdhash.cpp index 55145ce50..27ec699bb 100644 --- a/src/lib/pbkdf/pwdhash.cpp +++ b/src/lib/pbkdf/pwdhash.cpp @@ -30,6 +30,22 @@ namespace Botan { +void PasswordHash::derive_key(uint8_t out[], size_t out_len, + const char* password, size_t password_len, + const uint8_t salt[], size_t salt_len, + const uint8_t ad[], size_t ad_len, + const uint8_t key[], size_t key_len) const + { + BOTAN_UNUSED(ad, key); + + if(ad_len == 0 && key_len == 0) + return this->derive_key(out, out_len, + password, password_len, + salt, salt_len); + else + throw Not_Implemented("PasswordHash " + this->to_string() + " does not support AD or key"); + } + std::unique_ptr<PasswordHashFamily> PasswordHashFamily::create(const std::string& algo_spec, const std::string& provider) { diff --git a/src/lib/pbkdf/pwdhash.h b/src/lib/pbkdf/pwdhash.h index d57775e73..775e8b79c 100644 --- a/src/lib/pbkdf/pwdhash.h +++ b/src/lib/pbkdf/pwdhash.h @@ -74,6 +74,32 @@ class BOTAN_PUBLIC_API(2,8) PasswordHash virtual void derive_key(uint8_t out[], size_t out_len, const char* password, size_t password_len, const uint8_t salt[], size_t salt_len) const = 0; + + /** + * Derive a key from a password plus additional data and/or a secret key + * + * Currently this is only supported for Argon2. Using a non-empty AD or key + * with other algorithms will cause a Not_Implemented exception. + * + * @param out buffer to store the derived key, must be of out_len bytes + * @param out_len the desired length of the key to produce + * @param password the password to derive the key from + * @param password_len the length of password in bytes + * @param salt a randomly chosen salt + * @param salt_len length of salt in bytes + * @param ad some additional data + * @param ad_len length of ad in bytes + * @param key a secret key + * @param key_len length of key in bytes + * + * This function is const, but is not thread safe. Different threads should + * either use unique objects, or serialize all access. + */ + virtual void derive_key(uint8_t out[], size_t out_len, + const char* password, size_t password_len, + const uint8_t salt[], size_t salt_len, + const uint8_t ad[], size_t ad_len, + const uint8_t key[], size_t key_len) const; }; class BOTAN_PUBLIC_API(2,8) PasswordHashFamily diff --git a/src/tests/test_pbkdf.cpp b/src/tests/test_pbkdf.cpp index 28f656617..ecdf2afe7 100644 --- a/src/tests/test_pbkdf.cpp +++ b/src/tests/test_pbkdf.cpp @@ -20,10 +20,6 @@ #include <botan/scrypt.h> #endif -#if defined(BOTAN_HAS_ARGON2) - #include <botan/argon2.h> -#endif - #if defined(BOTAN_HAS_PBKDF_BCRYPT) #include <botan/bcrypt_pbkdf.h> #endif @@ -268,29 +264,8 @@ class Argon2_KAT_Tests final : public Text_Based_Test const std::vector<uint8_t> passphrase = vars.get_req_bin("Passphrase"); const std::vector<uint8_t> expected = vars.get_req_bin("Output"); - uint8_t family; - if(mode == "Argon2d") - family = 0; - else if(mode == "Argon2i") - family = 1; - else if(mode == "Argon2id") - family = 2; - else - throw Test_Error("Unknown Argon2 mode"); - Test::Result result(mode); - std::vector<uint8_t> output(expected.size()); - Botan::argon2(output.data(), output.size(), - reinterpret_cast<const char*>(passphrase.data()), - passphrase.size(), - salt.data(), salt.size(), - key.data(), key.size(), - ad.data(), ad.size(), - family, P, M, T); - - result.test_eq("derived key", output, expected); - auto pwdhash_fam = Botan::PasswordHashFamily::create(mode); if(!pwdhash_fam) @@ -299,18 +274,17 @@ class Argon2_KAT_Tests final : public Text_Based_Test return result; } - if(ad.size() == 0) - { - auto pwdhash = pwdhash_fam->from_params(M, T, P); + auto pwdhash = pwdhash_fam->from_params(M, T, P); - std::vector<uint8_t> pwdhash_derived(expected.size()); - pwdhash->derive_key(pwdhash_derived.data(), pwdhash_derived.size(), - reinterpret_cast<const char*>(passphrase.data()), - passphrase.size(), - salt.data(), salt.size()); + std::vector<uint8_t> pwdhash_derived(expected.size()); + pwdhash->derive_key(pwdhash_derived.data(), pwdhash_derived.size(), + reinterpret_cast<const char*>(passphrase.data()), + passphrase.size(), + salt.data(), salt.size(), + ad.data(), ad.size(), + key.data(), key.size()); - result.test_eq("pwdhash derived key", pwdhash_derived, expected); - } + result.test_eq("pwdhash derived key", pwdhash_derived, expected); return result; } |