24void pc_hmac_sha1_8(
const uint8_t *key,
size_t keylen,
const uint8_t msg[8], uint8_t out[
PC_SHA1_DIGEST_LEN])
26 uint8_t k[PC_BLOCK] = {0};
27 if (keylen > PC_BLOCK)
35 memcpy(k, key, keylen);
38 uint8_t inner_in[PC_BLOCK + 8];
39 for (
int i = 0; i < PC_BLOCK; i++)
41 inner_in[i] = k[i] ^ 0x36;
43 memcpy(inner_in + PC_BLOCK, msg, 8);
45 pc_sha1(inner_in,
sizeof(inner_in), inner);
48 for (
int i = 0; i < PC_BLOCK; i++)
50 outer_in[i] = k[i] ^ 0x5c;
53 pc_sha1(outer_in,
sizeof(outer_in), out);
56uint32_t pow10u(uint8_t n)
67uint32_t pc_hotp(
const uint8_t *key,
size_t keylen, uint64_t counter, uint8_t digits)
70 for (
int i = 7; i >= 0; i--)
72 msg[i] = (uint8_t)(counter & 0xFF);
76 pc_hmac_sha1_8(key, keylen, msg, mac);
79 uint32_t bin = ((uint32_t)(mac[off] & 0x7F) << 24) | ((uint32_t)mac[off + 1] << 16) |
80 ((uint32_t)mac[off + 2] << 8) | (uint32_t)mac[off + 3];
81 return bin % pow10u(digits);
84uint32_t pc_totp(
const uint8_t *key,
size_t keylen, uint64_t unix_time, uint32_t period, uint8_t digits)
90 return pc_hotp(key, keylen, unix_time / period, digits);
93bool pc_totp_verify(
const uint8_t *key,
size_t keylen, uint64_t unix_time, uint32_t code, uint32_t period,
94 uint8_t digits,
int window)
100 int64_t step = (int64_t)(unix_time / period);
101 for (
int w = -window; w <= window; w++)
103 int64_t c = step + w;
108 if (pc_hotp(key, keylen, (uint64_t)c, digits) == code)
116int pc_base32_decode(
const char *b32, uint8_t *out,
size_t cap)
125 for (
const char *p = b32; *p; p++)
129 if (c >=
'A' && c <=
'Z')
133 else if (c >=
'a' && c <=
'z')
137 else if (c >=
'2' && c <=
'7')
141 else if (c ==
'=' || c ==
' ' || c ==
'-')
149 buffer = (buffer << 5) | (uint32_t)val;
158 out[n++] = (uint8_t)((buffer >> bits) & 0xFF);
PC_CRYPTO_HOT void pc_sha1(const uint8_t *data, size_t len, uint8_t digest[PC_SHA1_DIGEST_LEN])
Compute a SHA-1 digest over an arbitrary byte buffer.
SHA-1 (FIPS 180-4) - one-shot digest.
#define PC_SHA1_DIGEST_LEN
SHA-1 digest length in bytes.
TOTP two-factor auth (RFC 6238) (PC_ENABLE_TOTP).