21constexpr int BLOCK = 64;
24void hmac_sha1_8(
const uint8_t *key,
size_t keylen,
const uint8_t msg[8], uint8_t out[
SHA1_DIGEST_LEN])
26 uint8_t k[BLOCK] = {0};
30 sha1(key, keylen, kh);
35 memcpy(k, key, keylen);
38 uint8_t inner_in[BLOCK + 8];
39 for (
int i = 0; i < BLOCK; i++)
40 inner_in[i] = k[i] ^ 0x36;
41 memcpy(inner_in + BLOCK, msg, 8);
43 sha1(inner_in,
sizeof(inner_in), inner);
46 for (
int i = 0; i < BLOCK; i++)
47 outer_in[i] = k[i] ^ 0x5c;
49 sha1(outer_in,
sizeof(outer_in), out);
52uint32_t pow10u(uint8_t n)
61uint32_t detws_hotp(
const uint8_t *key,
size_t keylen, uint64_t counter, uint8_t digits)
64 for (
int i = 7; i >= 0; i--)
66 msg[i] = (uint8_t)(counter & 0xFF);
70 hmac_sha1_8(key, keylen, msg, mac);
73 uint32_t bin = ((uint32_t)(mac[off] & 0x7F) << 24) | ((uint32_t)mac[off + 1] << 16) |
74 ((uint32_t)mac[off + 2] << 8) | (uint32_t)mac[off + 3];
75 return bin % pow10u(digits);
78uint32_t detws_totp(
const uint8_t *key,
size_t keylen, uint64_t unix_time, uint32_t period, uint8_t digits)
82 return detws_hotp(key, keylen, unix_time / period, digits);
85bool detws_totp_verify(
const uint8_t *key,
size_t keylen, uint64_t unix_time, uint32_t code, uint32_t period,
86 uint8_t digits,
int window)
90 int64_t step = (int64_t)(unix_time / period);
91 for (
int w = -window; w <= window; w++)
96 if (detws_hotp(key, keylen, (uint64_t)c, digits) == code)
102int detws_base32_decode(
const char *b32, uint8_t *out,
size_t cap)
109 for (
const char *p = b32; *p; p++)
113 if (c >=
'A' && c <=
'Z')
115 else if (c >=
'a' && c <=
'z')
117 else if (c >=
'2' && c <=
'7')
119 else if (c ==
'=' || c ==
' ' || c ==
'-')
123 buffer = (buffer << 5) | (uint32_t)val;
130 out[n++] = (uint8_t)((buffer >> bits) & 0xFF);
void sha1(const uint8_t *data, size_t len, uint8_t digest[SHA1_DIGEST_LEN])
Compute a SHA-1 digest over an arbitrary byte buffer.
Software SHA-1 implementation - no platform dependencies.
#define SHA1_DIGEST_LEN
SHA-1 digest length in bytes.
TOTP two-factor auth (RFC 6238) (DETWS_ENABLE_TOTP).