diff --git a/README-RU.md b/README-RU.md index 5460de0..b61fbb6 100644 --- a/README-RU.md +++ b/README-RU.md @@ -112,6 +112,13 @@ auto sig = hmac::get_hmac(key, payload, hmac::TypeHash::SHA256); secure_zero(key); // при необходимости: очистить после использования ``` +Чтобы сравнить два токена напрямую, используйте +`hmac::constant_time_equal` для защиты от атак по времени: + +```cpp +bool same = hmac::constant_time_equal(expected_token, user_token); // длины публичны +``` + ### HMAC (сырые бинарные данные) ```cpp @@ -269,21 +276,27 @@ try { ```cpp #include #include +#include int main() { std::string input = "grape"; std::string key = "12345"; - std::string hmac_sha256 = hmac::get_hmac(key, input, hmac::TypeHash::SHA256); - std::cout << "HMAC-SHA256: " << hmac_sha256 << std::endl; - - std::string hmac_sha512 = hmac::get_hmac(key, input, hmac::TypeHash::SHA512); - std::cout << "HMAC-SHA512: " << hmac_sha512 << std::endl; + std::string mac = hmac::get_hmac(key, input, hmac::TypeHash::SHA256); + if (hmac::constant_time_equal(mac, + "7632ac2e8ddedaf4b3e7ab195fefd17571c37c970e02e169195a158ef59e53ca")) { + std::cout << "MAC проверен\n"; + } return 0; } ``` +**Примечание:** `constant_time_equal` считает длину входных данных публичной и +время работы зависит от максимальной длины. Не проверяйте длины отдельно — +ранние проверки могут выдать информацию через побочные каналы времени +выполнения. + ## 📚 Полезные ссылки * Исходный код [SHA256](http://www.zedwood.com/article/cpp-sha256-function) diff --git a/README.md b/README.md index 83b4fac..5b6e189 100644 --- a/README.md +++ b/README.md @@ -141,6 +141,13 @@ std::vector sig = secure_zero(key); // optional: wipe after use ``` +To compare two tokens directly, use `hmac::constant_time_equal` for a +timing-safe check: + +```cpp +bool same = hmac::constant_time_equal(expected_token, user_token); // lengths are public +``` + ### HMAC (binary data: raw buffer) ```cpp @@ -326,8 +333,9 @@ int main() { } ``` -**Note:** avoid checking input lengths before calling `constant_time_equal`. -Early length comparisons can leak information through timing side channels. +**Note:** `constant_time_equal` treats input lengths as public and may run +longer for longer inputs. Avoid checking lengths separately—early length +comparisons can leak information through timing side channels. ## 📚 Resources diff --git a/include/hmac_cpp/hmac_utils.hpp b/include/hmac_cpp/hmac_utils.hpp index 898f18e..c393df9 100644 --- a/include/hmac_cpp/hmac_utils.hpp +++ b/include/hmac_cpp/hmac_utils.hpp @@ -24,6 +24,17 @@ namespace hmac_cpp { HMAC_CPP_API bool constant_time_equals(const uint8_t* a, size_t a_len, const uint8_t* b, size_t b_len); + /// \brief Alias for \c constant_time_equals. + /// \param a Pointer to first array. + /// \param a_len Length of the first array. + /// \param b Pointer to second array. + /// \param b_len Length of the second array. + /// \return true if both arrays are equal. + /// \note Avoids early length checks; input lengths are treated as public + /// and may influence timing. + HMAC_CPP_API bool constant_time_equal(const uint8_t* a, size_t a_len, + const uint8_t* b, size_t b_len); + /// \brief Compare vectors in constant time. /// \param a First vector. /// \param b Second vector. @@ -42,19 +53,7 @@ namespace hmac_cpp { reinterpret_cast(b.data()), b.size()); } - /// \brief Alias for constant_time_equals. - /// \param a Pointer to first array. - /// \param a_len Length of the first array. - /// \param b Pointer to second array. - /// \param b_len Length of the second array. - /// \return true if both arrays are equal. - /// \note Avoids early length checks to mitigate timing attacks. - inline bool constant_time_equal(const uint8_t* a, size_t a_len, - const uint8_t* b, size_t b_len) { - return constant_time_equals(a, a_len, b, b_len); - } - - /// \brief Alias for constant_time_equals on vectors. + /// \brief Alias for \c constant_time_equal on vectors. /// \param a First vector. /// \param b Second vector. /// \return true if both vectors are equal. @@ -63,7 +62,7 @@ namespace hmac_cpp { return constant_time_equal(a.data(), a.size(), b.data(), b.size()); } - /// \brief Alias for constant_time_equals on strings. + /// \brief Alias for \c constant_time_equal on strings. /// \param a First string. /// \param b Second string. /// \return true if both strings are equal. diff --git a/src/hmac_utils.cpp b/src/hmac_utils.cpp index 2ba6fad..a239c1b 100644 --- a/src/hmac_utils.cpp +++ b/src/hmac_utils.cpp @@ -21,6 +21,11 @@ namespace hmac_cpp { return diff == 0; } + bool constant_time_equal(const uint8_t* a, size_t a_len, + const uint8_t* b, size_t b_len) { + return constant_time_equals(a, a_len, b, b_len); + } + static TypeHash to_type_hash(Pbkdf2Hash prf) { switch (prf) { case Pbkdf2Hash::Sha1: return TypeHash::SHA1;