From 7432166d0c30a8cb4c347cf9c772cc45227069cd Mon Sep 17 00:00:00 2001 From: Aster Seker Date: Sat, 6 Sep 2025 00:19:13 +0300 Subject: [PATCH] feat(pbkdf2): add result struct --- README.md | 3 +++ include/hmac_cpp/hmac_utils.hpp | 39 +++++++++++++++++++++++++++++++++ test_all.cpp | 9 ++++++++ 3 files changed, 51 insertions(+) diff --git a/README.md b/README.md index 9040ab1..00c9fda 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,9 @@ Returns: Binary digest as `std::vector` std::string password = "password"; std::vector salt(16, 0x01); // at least 16 bytes std::vector dk = hmac::pbkdf2(password, salt, 1000, 32); +hmac::Pbkdf2Result stored{salt, 1000, dk}; +auto verify = hmac::pbkdf2(password, stored); +bool ok = hmac::constant_time_equals(verify.key, stored.key); ``` Parameters: diff --git a/include/hmac_cpp/hmac_utils.hpp b/include/hmac_cpp/hmac_utils.hpp index 28d2477..159948f 100644 --- a/include/hmac_cpp/hmac_utils.hpp +++ b/include/hmac_cpp/hmac_utils.hpp @@ -54,6 +54,12 @@ namespace hmac_cpp { /// \brief Hash choices for PBKDF2 enum class Pbkdf2Hash { Sha1, Sha256, Sha512 }; + struct Pbkdf2Result { + std::vector salt; + uint32_t iters; + std::vector key; + }; + /// \brief Derives a key from a password using PBKDF2 (RFC 8018) /// \param password_ptr Pointer to the password buffer /// \param password_len Length of the password in bytes @@ -106,6 +112,39 @@ namespace hmac_cpp { iterations, dk_len, prf); } + template + inline Pbkdf2Result pbkdf2( + const std::vector& password, + const Pbkdf2Result& params, + Pbkdf2Hash prf = Pbkdf2Hash::Sha256) { + static_assert(std::is_same::value || std::is_same::value, + "pbkdf2(vector) supports only char or uint8_t"); + auto key = pbkdf2(password.data(), password.size(), + params.salt.data(), params.salt.size(), + params.iters, params.key.size(), prf); + return {params.salt, params.iters, std::move(key)}; + } + + inline Pbkdf2Result pbkdf2( + const std::string& password, + const Pbkdf2Result& params, + Pbkdf2Hash prf = Pbkdf2Hash::Sha256) { + auto key = pbkdf2(password.data(), password.size(), + params.salt.data(), params.salt.size(), + params.iters, params.key.size(), prf); + return {params.salt, params.iters, std::move(key)}; + } + + inline Pbkdf2Result pbkdf2( + const secure_buffer& password, + const Pbkdf2Result& params, + Pbkdf2Hash prf = Pbkdf2Hash::Sha256) { + auto key = pbkdf2(password.data(), password.size(), + params.salt.data(), params.salt.size(), + params.iters, params.key.size(), prf); + return {params.salt, params.iters, std::move(key)}; + } + /// \brief Derives PBKDF2 into caller-provided buffer using selected hash. /// \param prf Hash function to use (SHA1, SHA256, SHA512) /// \param password_ptr Pointer to the password buffer diff --git a/test_all.cpp b/test_all.cpp index 0fa48a0..65543d6 100644 --- a/test_all.cpp +++ b/test_all.cpp @@ -361,6 +361,15 @@ TEST(PBKDF2Test, SHA256WithValidSalt) { EXPECT_TRUE(hmac::constant_time_equals(dk, ref)); } +TEST(PBKDF2ResultTest, ComputesFromStoredParams) { + auto salt = from_hex("000102030405060708090a0b0c0d0e0f"); + std::string salt_str(salt.begin(), salt.end()); + auto dk = hmac::pbkdf2(std::string("password"), salt_str, 2, 32, hmac::Pbkdf2Hash::Sha256); + hmac::Pbkdf2Result stored{salt, 2, dk}; + auto out = hmac::pbkdf2(std::string("password"), stored); + EXPECT_TRUE(hmac::constant_time_equals(out.key, stored.key)); +} + TEST(PBKDF2BufferApiTest, SHA256ArrayOutput) { auto salt = from_hex("000102030405060708090a0b0c0d0e0f"); std::string salt_str(salt.begin(), salt.end());