diff --git a/hmac_utils.cpp b/hmac_utils.cpp index 46d67a3..f7b53ca 100644 --- a/hmac_utils.cpp +++ b/hmac_utils.cpp @@ -1,6 +1,7 @@ #include "hmac_utils.hpp" #include #include +#include namespace hmac { @@ -133,7 +134,9 @@ namespace hmac { } uint64_t counter = timestamp / period; if (token == get_hotp_code(key_ptr, key_len, counter, digits, hash_type)) return true; - if (token == get_hotp_code(key_ptr, key_len, counter + 1, digits, hash_type)) return true; + if (counter != std::numeric_limits::max() && + token == get_hotp_code(key_ptr, key_len, counter + 1, digits, hash_type)) + return true; if (counter > 0 && token == get_hotp_code(key_ptr, key_len, counter - 1, digits, hash_type)) return true; @@ -157,7 +160,9 @@ namespace hmac { uint64_t timestamp = static_cast(std::time(nullptr)); uint64_t counter = timestamp / period; if (token == get_hotp_code(key_ptr, key_len, counter, digits, hash_type)) return true; - if (token == get_hotp_code(key_ptr, key_len, counter + 1, digits, hash_type)) return true; + if (counter != std::numeric_limits::max() && + token == get_hotp_code(key_ptr, key_len, counter + 1, digits, hash_type)) + return true; if (counter > 0 && token == get_hotp_code(key_ptr, key_len, counter - 1, digits, hash_type)) return true; diff --git a/hmac_utils.hpp b/hmac_utils.hpp index 446c837..7adace4 100644 --- a/hmac_utils.hpp +++ b/hmac_utils.hpp @@ -175,7 +175,9 @@ namespace hmac { /// \param period Time step in seconds (default: 30) /// \param digits Expected number of digits in the OTP (default: 6) /// \param hash_type Hash algorithm to use (SHA1, SHA256, SHA512). Default is SHA1 - /// \return true if the token is valid within [-1, 0, +1] time step range; false otherwise + /// \return true if the token is valid within [-1, 0, +1] time step range; false otherwise. + /// The +1 step check is skipped when the computed counter equals + /// std::numeric_limits::max(). /// \throws std::invalid_argument if period <= 0 or digits not in [1,9] bool is_totp_token_valid( int token, @@ -194,7 +196,9 @@ namespace hmac { /// \param period Time step in seconds (default: 30) /// \param digits Number of digits in the OTP (default: 6) /// \param hash_type Hash function to use (default: SHA1) - /// \return true if the token is valid within [-1, 0, +1] time step range; false otherwise + /// \return true if the token is valid within [-1, 0, +1] time step range; false otherwise. + /// The +1 step check is skipped when the computed counter equals + /// std::numeric_limits::max(). /// \throws std::invalid_argument if period <= 0 or digits not in [1,9] template inline bool is_totp_token_valid( @@ -216,7 +220,9 @@ namespace hmac { /// \param period Time step in seconds (default: 30) /// \param digits Number of digits in the OTP (default: 6) /// \param hash_type Hash function to use (default: SHA1) - /// \return true if the token is valid within [-1, 0, +1] time step range; false otherwise + /// \return true if the token is valid within [-1, 0, +1] time step range; false otherwise. + /// The +1 step check is skipped when the computed counter equals + /// std::numeric_limits::max(). /// \throws std::invalid_argument if period <= 0 or digits not in [1,9] inline bool is_totp_token_valid( int token, @@ -235,7 +241,9 @@ namespace hmac { /// \param period Time step in seconds (default: 30) /// \param digits Expected number of digits in the OTP (default: 6) /// \param hash_type Hash algorithm to use (default: SHA1) - /// \return true if the token is valid within [-1, 0, +1] time step range; false otherwise + /// \return true if the token is valid within [-1, 0, +1] time step range; false otherwise. + /// The +1 step check is skipped when the computed counter equals + /// std::numeric_limits::max(). /// \throws std::invalid_argument if period <= 0 or digits not in [1,9] bool is_totp_token_valid( int token, @@ -252,7 +260,9 @@ namespace hmac { /// \param period Time step in seconds (default: 30) /// \param digits Number of digits in the OTP (default: 6) /// \param hash_type Hash function to use (default: SHA1) - /// \return true if the token is valid within [-1, 0, +1] time step range; false otherwise + /// \return true if the token is valid within [-1, 0, +1] time step range; false otherwise. + /// The +1 step check is skipped when the computed counter equals + /// std::numeric_limits::max(). /// \throws std::invalid_argument if period <= 0 or digits not in [1,9] template inline bool is_totp_token_valid( @@ -272,7 +282,9 @@ namespace hmac { /// \param period Time step in seconds (default: 30) /// \param digits Number of digits in the OTP (default: 6) /// \param hash_type Hash function to use (default: SHA1) - /// \return true if the token is valid within [-1, 0, +1] time step range; false otherwise + /// \return true if the token is valid within [-1, 0, +1] time step range; false otherwise. + /// The +1 step check is skipped when the computed counter equals + /// std::numeric_limits::max(). /// \throws std::invalid_argument if period <= 0 or digits not in [1,9] inline bool is_totp_token_valid( int token, diff --git a/test_totp.cpp b/test_totp.cpp index 3e7d1ba..1b37416 100644 --- a/test_totp.cpp +++ b/test_totp.cpp @@ -20,6 +20,17 @@ int main() { bool valid_max = hmac::is_totp_token_valid(token_max, key.data(), key.size(), early_timestamp, period, digits, hmac::TypeHash::SHA1); assert(!valid_max); - std::cout << "TOTP early timestamp test passed" << std::endl; + // At maximum timestamp, ensure overflow does not validate counter 0 token + uint64_t max_timestamp = std::numeric_limits::max(); + int token_zero = hmac::get_hotp_code(key.data(), key.size(), 0, digits, hmac::TypeHash::SHA1); + bool valid_zero_at_max = hmac::is_totp_token_valid(token_zero, key.data(), key.size(), max_timestamp, 1, digits, hmac::TypeHash::SHA1); + assert(!valid_zero_at_max); + + // Token for max counter should still be valid at that timestamp + int token_max_ts = hmac::get_hotp_code(key.data(), key.size(), max_counter, digits, hmac::TypeHash::SHA1); + bool valid_max_ts = hmac::is_totp_token_valid(token_max_ts, key.data(), key.size(), max_timestamp, 1, digits, hmac::TypeHash::SHA1); + assert(valid_max_ts); + + std::cout << "TOTP tests passed" << std::endl; return 0; }