From 158ebe90c78f5958bcf99610ed47e39527efc97c Mon Sep 17 00:00:00 2001 From: Aster Seker Date: Sat, 6 Sep 2025 07:50:16 +0300 Subject: [PATCH] feat(hkdf): add secure buffer hkdf helpers Add hkdf_extract_sha256_secure and hkdf_expand_sha256_secure returning secure_buffer and switch hkdf_key_iv_256 to use secure buffers. --- include/hmac_cpp/hmac_utils.hpp | 41 +++++++++++++++++++++++ src/hmac_utils.cpp | 58 ++++++++++++++++++++++----------- 2 files changed, 80 insertions(+), 19 deletions(-) diff --git a/include/hmac_cpp/hmac_utils.hpp b/include/hmac_cpp/hmac_utils.hpp index 9186070..6120367 100644 --- a/include/hmac_cpp/hmac_utils.hpp +++ b/include/hmac_cpp/hmac_utils.hpp @@ -473,6 +473,22 @@ namespace hmac_cpp { return hkdf_extract_sha256(ikm.data(), ikm.size(), salt.data(), salt.size()); } + HMAC_CPP_API secure_buffer hkdf_extract_sha256_secure( + const void* ikm_ptr, size_t ikm_len, + const void* salt_ptr, size_t salt_len); + + inline secure_buffer hkdf_extract_sha256_secure( + const secure_buffer& ikm, + const secure_buffer& salt) { + return hkdf_extract_sha256_secure(ikm.data(), ikm.size(), salt.data(), salt.size()); + } + + inline secure_buffer hkdf_extract_sha256_secure( + const std::vector& ikm, + const std::vector& salt) { + return hkdf_extract_sha256_secure(ikm.data(), ikm.size(), salt.data(), salt.size()); + } + /// \brief HKDF expand step using SHA-256. /// \param prk_ptr Pointer to the pseudorandom key. /// \param prk_len Length of the pseudorandom key. @@ -497,6 +513,25 @@ namespace hmac_cpp { return hkdf_expand_sha256(prk.data(), prk.size(), info.data(), info.size(), L); } + HMAC_CPP_API secure_buffer hkdf_expand_sha256_secure( + const void* prk_ptr, size_t prk_len, + const void* info_ptr, size_t info_len, + size_t L); + + inline secure_buffer hkdf_expand_sha256_secure( + const secure_buffer& prk, + const secure_buffer& info, + size_t L) { + return hkdf_expand_sha256_secure(prk.data(), prk.size(), info.data(), info.size(), L); + } + + inline secure_buffer hkdf_expand_sha256_secure( + const std::vector& prk, + const std::vector& info, + size_t L) { + return hkdf_expand_sha256_secure(prk.data(), prk.size(), info.data(), info.size(), L); + } + /// \brief Holds a 32-byte key and 12-byte IV produced by HKDF. struct KeyIv { std::array key; ///< Derived symmetric key @@ -525,6 +560,12 @@ namespace hmac_cpp { return hkdf_key_iv_256(ikm.data(), ikm.size(), salt.data(), salt.size(), context); } + inline KeyIv hkdf_key_iv_256(const secure_buffer& ikm, + const secure_buffer& salt, + const std::string& context) { + return hkdf_key_iv_256(ikm.data(), ikm.size(), salt.data(), salt.size(), context); + } + /// \brief Generates a time-based HMAC-SHA256 token /// \param key Secret key used for HMAC /// \param interval_sec Interval in seconds that defines token rotation. Must be positive. Default is 60 seconds diff --git a/src/hmac_utils.cpp b/src/hmac_utils.cpp index 9b2083f..a16d10e 100644 --- a/src/hmac_utils.cpp +++ b/src/hmac_utils.cpp @@ -241,7 +241,7 @@ namespace hmac_cpp { return dk; } - std::vector hkdf_extract_sha256( + secure_buffer hkdf_extract_sha256_secure( const void* ikm_ptr, size_t ikm_len, const void* salt_ptr, size_t salt_len) { std::vector salt_buf; @@ -250,11 +250,19 @@ namespace hmac_cpp { salt_ptr = salt_buf.data(); salt_len = salt_buf.size(); } - auto prk = get_hmac(salt_ptr, salt_len, ikm_ptr, ikm_len, TypeHash::SHA256); + secure_buffer prk( + get_hmac(salt_ptr, salt_len, ikm_ptr, ikm_len, TypeHash::SHA256)); return prk; } - std::vector hkdf_expand_sha256( + std::vector hkdf_extract_sha256( + const void* ikm_ptr, size_t ikm_len, + const void* salt_ptr, size_t salt_len) { + auto prk = hkdf_extract_sha256_secure(ikm_ptr, ikm_len, salt_ptr, salt_len); + return std::vector(prk.begin(), prk.end()); + } + + secure_buffer hkdf_expand_sha256_secure( const void* prk_ptr, size_t prk_len, const void* info_ptr, size_t info_len, size_t L) { @@ -264,21 +272,25 @@ namespace hmac_cpp { if (L > 255 * HashLen) throw std::invalid_argument("HKDF: L too large"); - std::vector okm; - okm.reserve(L); - std::vector previous; + secure_buffer okm(L); + secure_buffer previous; size_t n = (L + HashLen - 1) / HashLen; + size_t offset = 0; for (size_t i = 1; i <= n; ++i) { - std::vector input(previous.begin(), previous.end()); - if (info_ptr && info_len) - input.insert(input.end(), - reinterpret_cast(info_ptr), - reinterpret_cast(info_ptr) + info_len); - input.push_back(static_cast(i)); - auto t = get_hmac(prk_ptr, prk_len, input.data(), input.size(), TypeHash::SHA256); - size_t take = (i == n) ? (L - okm.size()) : t.size(); - okm.insert(okm.end(), t.begin(), t.begin() + take); - previous.assign(t.begin(), t.end()); + size_t info_bytes = (info_ptr && info_len) ? info_len : 0; + size_t input_len = previous.size() + info_bytes + 1; + secure_buffer input(input_len); + if (previous.size()) + std::memcpy(input.data(), previous.data(), previous.size()); + if (info_bytes) + std::memcpy(input.data() + previous.size(), info_ptr, info_len); + input[input_len - 1] = static_cast(i); + secure_buffer t( + get_hmac(prk_ptr, prk_len, input.data(), input.size(), TypeHash::SHA256)); + size_t take = (i == n) ? (L - offset) : t.size(); + std::memcpy(okm.data() + offset, t.data(), take); + offset += take; + previous = t; secure_zero(t.data(), t.size()); secure_zero(input.data(), input.size()); } @@ -286,12 +298,20 @@ namespace hmac_cpp { return okm; } + std::vector hkdf_expand_sha256( + const void* prk_ptr, size_t prk_len, + const void* info_ptr, size_t info_len, + size_t L) { + auto okm = hkdf_expand_sha256_secure(prk_ptr, prk_len, info_ptr, info_len, L); + return std::vector(okm.begin(), okm.end()); + } + KeyIv hkdf_key_iv_256(const void* ikm_ptr, size_t ikm_len, const void* salt_ptr, size_t salt_len, const std::string& context) { - auto prk = hkdf_extract_sha256(ikm_ptr, ikm_len, salt_ptr, salt_len); - auto okm = hkdf_expand_sha256(prk.data(), prk.size(), - context.data(), context.size(), 44); + auto prk = hkdf_extract_sha256_secure(ikm_ptr, ikm_len, salt_ptr, salt_len); + auto okm = hkdf_expand_sha256_secure(prk.data(), prk.size(), + context.data(), context.size(), 44); KeyIv out{}; std::copy(okm.begin(), okm.begin() + 32, out.key.begin()); std::copy(okm.begin() + 32, okm.begin() + 44, out.iv.begin());