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
21 changes: 15 additions & 6 deletions hmac_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@
#include <stdexcept>

namespace hmac {

bool constant_time_equals(const std::string &a, const std::string &b) {
if (a.size() != b.size()) return false;
unsigned char diff = 0;
for (size_t i = 0; i < a.size(); ++i) {
diff |= static_cast<unsigned char>(a[i]) ^ static_cast<unsigned char>(b[i]);
}
return diff == 0;
}

std::string generate_time_token(const std::string &key, int interval_sec, TypeHash hash_type) {
if (interval_sec <= 0) {
Expand All @@ -25,9 +34,9 @@ namespace hmac {
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;
if (token == get_hmac(key, std::to_string(rounded + interval_sec), hash_type)) return true;
if (constant_time_equals(token, get_hmac(key, std::to_string(rounded), hash_type))) return true;
if (constant_time_equals(token, get_hmac(key, std::to_string(rounded - interval_sec), hash_type))) return true;
if (constant_time_equals(token, get_hmac(key, std::to_string(rounded + interval_sec), hash_type))) return true;
return false;
}

Expand Down Expand Up @@ -55,11 +64,11 @@ namespace hmac {
std::time_t rounded = (now / interval_sec) * interval_sec;
std::string prefix = "|" + fingerprint;
std::string payload = std::to_string(rounded) + prefix;
if (token == get_hmac(key, payload, hash_type)) return true;
if (constant_time_equals(token, get_hmac(key, payload, hash_type))) return true;
payload = std::to_string(rounded - interval_sec) + prefix;
if (token == get_hmac(key, payload, hash_type)) return true;
if (constant_time_equals(token, get_hmac(key, payload, hash_type))) return true;
payload = std::to_string(rounded + interval_sec) + prefix;
if (token == get_hmac(key, payload, hash_type)) return true;
if (constant_time_equals(token, get_hmac(key, payload, hash_type))) return true;
return false;
}

Expand Down
6 changes: 6 additions & 0 deletions hmac_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@

namespace hmac {

/// \brief Compares two strings in constant time
/// \param a First string
/// \param b Second string
/// \return true if both strings are equal
bool constant_time_equals(const std::string &a, const std::string &b);

/// \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
Expand Down
Loading