aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/api_ref/pbkdf.rst10
-rw-r--r--src/lib/pbkdf/argon2/argon2.h6
-rw-r--r--src/lib/pbkdf/argon2/argon2pwhash.cpp14
-rw-r--r--src/lib/pbkdf/pwdhash.cpp16
-rw-r--r--src/lib/pbkdf/pwdhash.h26
-rw-r--r--src/tests/test_pbkdf.cpp44
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;
}