TOTP implementation

68 views
Skip to first unread message

Aravindh B

unread,
Aug 3, 2023, 5:51:20 AM8/3/23
to Crypto++ Users
Need to get some information how counter value is handled in this library.

std::string generateTOTP(const std::string& secretKey) {

using namespace CryptoPP;
const int timeStep = 30; // Time step in seconds
SecByteBlock key(HMAC<SHA1>::DEFAULT_KEYLENGTH);
StringSource(secretKey, true, new Base32Decoder(new ArraySink(key, key.size())));

// Get the current time in 30-second intervals (TOTP time step)
std::time_t currentTime = std::time(nullptr);
uint64_t counter = static_cast<uint64_t>(currentTime) / timeStep;
const size_t byteArraySize = sizeof(counter);
byte* byteArray = new byte[byteArraySize];

//Big endian representation
for (size_t i = 0; i < byteArraySize; ++i) {
byteArray[sizeof(counter) - 1 - i] = static_cast<byte>((counter >> (8 * i)) & 0xFF);
}

// Calculate the HMAC-SHA1 using the secret key and the counter bytes
byte mac[CryptoPP::HMAC<CryptoPP::SHA1>::DIGESTSIZE];
CryptoPP::HMAC<CryptoPP::SHA1> hmac(key, sizeof(key));
hmac.Update(byteArray, sizeof(byteArraySize));
hmac.Final(mac);

// Generate the TOTP value from the last 4 bits of the HMAC-SHA1 result
int offset = mac[CryptoPP::HMAC<CryptoPP::SHA1>::DIGESTSIZE - 1] & 0xF;
uint32_t otpValue = (mac[offset] & 0x7F) << 24 |
(mac[offset + 1] & 0xFF) << 16 |
(mac[offset + 2] & 0xFF) << 8 |
(mac[offset + 3] & 0xFF);

// Convert the OTP value to a 6-digit OTP (modulo 10^6)
otpValue %= 1000000;

//Format the OTP as a 6-digit string with leading zeros if needed
std::string otp = std::to_string(otpValue);
otp.insert(otp.begin(), 6 - otp.size(), '0');
delete[] byteArray;

return otp;
}

This code have issues with hmac.update(). Seems problem with counter value.Does anyone help to generate correct otp?

Steven Green

unread,
Aug 4, 2023, 9:14:12 AM8/4/23
to cryptop...@googlegroups.com

Shouldn't...

hmac.Update(byteArray, sizeof(byteArraySize));

be simply..

hmac.Update(byteArray, byteArraySize);

Otherwise you passing in sizeof(size_t) rather than the size of the byteArray (which is sizeof(uint64_t)). Although on a 64 bit system I would expect them both to be 8 bytes, so maybe there is another problem.

Otherwise the function looks very similar to what I have.

- Steven

--
You received this message because you are subscribed to the Google Groups "Crypto++ Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cryptopp-user...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/cryptopp-users/5cc93e58-cf8b-41fd-9855-8b84e707b19fn%40googlegroups.com.

phamba...@gmail.com

unread,
Aug 4, 2023, 1:28:39 PM8/4/23
to Crypto++ Users
Also, their version of Base32Decoder uses DUDE instead of RFC 4648.
Reply all
Reply to author
Forward
Message has been deleted
Message has been deleted
0 new messages