Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 26 additions & 6 deletions hmac_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ namespace hmac {
if (interval_sec <= 0) {
throw std::invalid_argument("interval_sec must be positive");
}
auto now = std::time(nullptr);
std::time_t now = std::time(nullptr);
if (now == static_cast<std::time_t>(-1)) {
throw std::runtime_error("std::time failed");
}
std::time_t rounded = (now / interval_sec) * interval_sec;
return get_hmac(key, std::to_string(rounded), hash_type);
}
Expand All @@ -17,7 +20,10 @@ namespace hmac {
if (interval_sec <= 0) {
throw std::invalid_argument("interval_sec must be positive");
}
auto now = std::time(nullptr);
std::time_t now = std::time(nullptr);
if (now == static_cast<std::time_t>(-1)) {
throw std::runtime_error("std::time failed");
}
std::time_t rounded = (now / interval_sec) * interval_sec;
if (token == get_hmac(key, std::to_string(rounded), hash_type)) return true;
if (token == get_hmac(key, std::to_string(rounded - interval_sec), hash_type)) return true;
Expand All @@ -29,7 +35,10 @@ namespace hmac {
if (interval_sec <= 0) {
throw std::invalid_argument("interval_sec must be positive");
}
auto now = std::time(nullptr);
std::time_t now = std::time(nullptr);
if (now == static_cast<std::time_t>(-1)) {
throw std::runtime_error("std::time failed");
}
std::time_t rounded = (now / interval_sec) * interval_sec;
std::string payload = std::to_string(rounded) + "|" + fingerprint;
return get_hmac(key, payload, hash_type);
Expand All @@ -39,7 +48,10 @@ namespace hmac {
if (interval_sec <= 0) {
throw std::invalid_argument("interval_sec must be positive");
}
auto now = std::time(nullptr);
std::time_t now = std::time(nullptr);
if (now == static_cast<std::time_t>(-1)) {
throw std::runtime_error("std::time failed");
}
std::time_t rounded = (now / interval_sec) * interval_sec;
std::string prefix = "|" + fingerprint;
std::string payload = std::to_string(rounded) + prefix;
Expand Down Expand Up @@ -112,7 +124,11 @@ namespace hmac {
if (digits < 1 || digits > 9) {
throw std::invalid_argument("TOTP: digits must be in range [1, 9]");
}
uint64_t timestamp = static_cast<uint64_t>(std::time(nullptr));
std::time_t now = std::time(nullptr);
if (now == static_cast<std::time_t>(-1)) {
throw std::runtime_error("std::time failed");
}
uint64_t timestamp = static_cast<uint64_t>(now);
return get_totp_code_at(key_ptr, key_len, timestamp, period, digits, hash_type);
}

Expand Down Expand Up @@ -154,7 +170,11 @@ namespace hmac {
if (digits < 1 || digits > 9) {
throw std::invalid_argument("TOTP: digits must be in range [1, 9]");
}
uint64_t timestamp = static_cast<uint64_t>(std::time(nullptr));
std::time_t now = std::time(nullptr);
if (now == static_cast<std::time_t>(-1)) {
throw std::runtime_error("std::time failed");
}
uint64_t timestamp = static_cast<uint64_t>(now);
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;
Expand Down
10 changes: 10 additions & 0 deletions hmac_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace hmac {
/// \param interval_sec Interval in seconds that defines token rotation. Must be positive. Default is 60 seconds
/// \param hash_type Hash function to use (SHA1, SHA256, SHA512). Default is SHA256
/// \return Hex-encoded HMAC-SHA256 of the rounded time value
/// \throws std::runtime_error if the system time cannot be retrieved
std::string generate_time_token(const std::string &key, int interval_sec = 60, TypeHash hash_type = TypeHash::SHA256);

/// \brief Validates a time-based HMAC-SHA256 token with ±1 interval tolerance
Expand All @@ -20,6 +21,7 @@ namespace hmac {
/// \param interval_sec Interval in seconds that defines token rotation. Must be positive. Default is 60 seconds
/// \param hash_type Hash function to use (SHA1, SHA256, SHA512). Default is SHA256
/// \return true if the token is valid within the ±1 interval range; false otherwise
/// \throws std::runtime_error if the system time cannot be retrieved
bool is_token_valid(const std::string &token, const std::string &key, int interval_sec = 60, TypeHash hash_type = TypeHash::SHA256);

/// \brief Generates a time-based HMAC-SHA256 token with fingerprint binding
Expand All @@ -28,6 +30,7 @@ namespace hmac {
/// \param interval_sec Interval in seconds that defines token rotation. Must be positive. Default is 60 seconds
/// \param hash_type Hash function to use (SHA1, SHA256, SHA512). Default is SHA256
/// \return Hex-encoded HMAC-SHA256 of the concatenated timestamp and fingerprint
/// \throws std::runtime_error if the system time cannot be retrieved
std::string generate_time_token(const std::string &key, const std::string &fingerprint, int interval_sec = 60, TypeHash hash_type = TypeHash::SHA256);

/// \brief Validates a fingerprint-bound HMAC-SHA256 token with ±1 interval tolerance
Expand All @@ -37,6 +40,7 @@ namespace hmac {
/// \param interval_sec Interval in seconds that defines token rotation. Must be positive. Default is 60 seconds
/// \param hash_type Hash function to use (SHA1, SHA256, SHA512). Default is SHA256
/// \return true if the token is valid within the ±1 interval range; false otherwise
/// \throws std::runtime_error if the system time cannot be retrieved
bool is_token_valid(const std::string &token, const std::string &key, const std::string &fingerprint, int interval_sec = 60, TypeHash hash_type = TypeHash::SHA256);

/// \brief Computes HOTP code based on HMAC as defined in RFC 4226
Expand Down Expand Up @@ -136,6 +140,7 @@ namespace hmac {
/// \param hash_type Hash function to use (default: SHA1).
/// \return TOTP code as an integer.
/// \throws std::invalid_argument if period <= 0 or digits not in [1,9].
/// \throws std::runtime_error if the system time cannot be retrieved.
int get_totp_code(
const void* key_ptr,
size_t key_len,
Expand All @@ -151,6 +156,7 @@ namespace hmac {
/// \param hash_type Hash function to use (default: SHA1)
/// \return TOTP code as an integer
/// \throws std::invalid_argument if period <= 0 or digits not in [1,9]
/// \throws std::runtime_error if the system time cannot be retrieved
template<typename T>
inline int get_totp_code(const std::vector<T>& key, int period = 30, int digits = 6, TypeHash hash_type = TypeHash::SHA1) {
return get_totp_code(key.data(), key.size(), period, digits, hash_type);
Expand All @@ -163,6 +169,7 @@ namespace hmac {
/// \param hash_type Hash function to use (default: SHA1)
/// \return TOTP code as an integer
/// \throws std::invalid_argument if period <= 0 or digits not in [1,9]
/// \throws std::runtime_error if the system time cannot be retrieved
inline int get_totp_code(const std::string& key, int period = 30, int digits = 6, TypeHash hash_type = TypeHash::SHA1) {
return get_totp_code(key.data(), key.size(), period, digits, hash_type);
}
Expand Down Expand Up @@ -237,6 +244,7 @@ namespace hmac {
/// \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
/// \throws std::invalid_argument if period <= 0 or digits not in [1,9]
/// \throws std::runtime_error if the system time cannot be retrieved
bool is_totp_token_valid(
int token,
const void* key_ptr,
Expand All @@ -254,6 +262,7 @@ namespace hmac {
/// \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
/// \throws std::invalid_argument if period <= 0 or digits not in [1,9]
/// \throws std::runtime_error if the system time cannot be retrieved
template<typename T>
inline bool is_totp_token_valid(
int token,
Expand All @@ -274,6 +283,7 @@ namespace hmac {
/// \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
/// \throws std::invalid_argument if period <= 0 or digits not in [1,9]
/// \throws std::runtime_error if the system time cannot be retrieved
inline bool is_totp_token_valid(
int token,
const std::string& key,
Expand Down
Loading