class TOTP {
public:
TOTP(const uint8_t hmacKey, int keyLength, int timeStep = 30);
TOTP(const String &hmacKey, int timeStep = 30);
~TOTP();
const char getCode(long timeStamp);
const char *getCodeFromSteps(long steps);
private:
uint8_t _hmacKey;
int _keyLength;
int _timeStep;
uint8_t _byteArray[8];
uint8_t _hash;
int _offset;
long _truncatedHash;
char _code[7];
long _steps;
};
// Init the library with the private key, its length and the timeStep duration
TOTP::TOTP(const uint8_t hmacKey, int keyLength, int timeStep): _keyLength(keyLength), _timeStep(timeStep) {
_hmacKey = (uint8_t ) malloc(_keyLength);
if(_hmacKey != NULL) memcpy(_hmacKey, hmacKey, keyLength);
}
I made some changes to your code for my own use, and publish it here, maybe some others can use it. The changes I made:
TOTP.h: `// OpenAuthentication Time-based One-time Password Algorithm (RFC 6238) // Arduino Library // // Luca Dentella (http://www.lucadentella.it)
include "Arduino.h"
ifndef _TOTP_H
define _TOTP_H
class TOTP { public: TOTP(const uint8_t hmacKey, int keyLength, int timeStep = 30); TOTP(const String &hmacKey, int timeStep = 30); ~TOTP(); const char getCode(long timeStamp); const char *getCodeFromSteps(long steps);
private: uint8_t _hmacKey; int _keyLength; int _timeStep; uint8_t _byteArray[8]; uint8_t _hash; int _offset; long _truncatedHash; char _code[7]; long _steps; };
endif`
TOTP.cpp: `// OpenAuthentication Time-based One-time Password Algorithm (RFC 6238) // For the complete description of the algorithm see // http://tools.ietf.org/html/rfc4226#section-5.3 // // Luca Dentella (http://www.lucadentella.it)
include "TOTP.h"
include "sha1.h"
// Init the library with the private key, its length and the timeStep duration TOTP::TOTP(const uint8_t hmacKey, int keyLength, int timeStep): _keyLength(keyLength), _timeStep(timeStep) { _hmacKey = (uint8_t ) malloc(_keyLength); if(_hmacKey != NULL) memcpy(_hmacKey, hmacKey, keyLength); }
TOTP::TOTP(const String &hmacKey, int timeStep): _timeStep(timeStep) { _keyLength = hmacKey.length(); _hmacKey = (uint8_t *) strdup(hmacKey.c_str());
}
TOTP::~TOTP() { free(_hmacKey); }
// Generate a code, using the timestamp provided const char *TOTP::getCode(long timeStamp) {
long steps = timeStamp / _timeStep; return steps != _steps ? getCodeFromSteps(steps) : _code; }
// Generate a code, using the number of steps provided const char *TOTP::getCodeFromSteps(long steps) {
// STEP 0, map the number of steps in a 8-bytes array (counter value) _byteArray[0] = 0x00; _byteArray[1] = 0x00; _byteArray[2] = 0x00; _byteArray[3] = 0x00; _byteArray[4] = (int)((steps >> 24) & 0xFF); _byteArray[5] = (int)((steps >> 16) & 0xFF); _byteArray[6] = (int)((steps >> 8) & 0XFF); _byteArray[7] = (int)((steps & 0XFF));
// STEP 1, get the HMAC-SHA1 hash from counter and key
Sha1.initHmac(_hmacKey, _keyLength); Sha1.write(_byteArray, 8); _hash = Sha1.resultHmac();
// STEP 2, apply dynamic truncation to obtain a 4-bytes string _offset = _hash[20 - 1] & 0xF; _truncatedHash = 0; for (int j = 0; j < 4; ++j) { _truncatedHash <<= 8; _truncatedHash |= _hash[_offset + j]; }
// STEP 3, compute the OTP value _truncatedHash &= 0x7FFFFFFF; _truncatedHash %= 1000000;
// convert the value in string, with heading zeroes sprintf(_code, "%06ld", _truncatedHash); _steps = steps; return _code; }`