From 6e1722c70e192b0a6501c06e49a7328048f4f8be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20Gallou=C3=ABt?= Date: Mon, 6 Jan 2025 12:36:04 +0100 Subject: [PATCH] Add base32 encoded TOTP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Adrien Gallouët --- README.md | 9 +++++++++ secret.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 53acca0..36118e1 100644 --- a/README.md +++ b/README.md @@ -158,6 +158,15 @@ Add a TOTP token: Passphrase: $ 123456 +Add a base32 encoded TOTP token: + + $ echo JBSWY3DPEHPK3PXP | secret set test/totp32 + Passphrase: + + $ secret show test/totp32 + Passphrase: + $ 123456 + Derive a deterministic (a.k.a. unstored) secret: $ secret pass me@domain.com diff --git a/secret.c b/secret.c index 7d86c3f..f0f1323 100644 --- a/secret.c +++ b/secret.c @@ -491,13 +491,13 @@ s_sha1(uint8_t *digest, uint8_t *buf, size_t len) static void s_totp(const char *secret, size_t len) { + if (!len || len > 64) + return; + uint8_t h[20]; uint8_t ki[64 + 8] = {0}; uint8_t ko[64 + 20] = {0}; - if (!len || len > 64) - return; - memcpy(ki, secret, len); memcpy(ko, secret, len); @@ -519,6 +519,52 @@ s_totp(const char *secret, size_t len) s_write(1, tmp, 6); } +static unsigned +s_b32(char c) +{ + if (c >= 'A' && c <= 'Z') { + return c - 'A'; + } else if (c >= '2' && c <= '9') { + return c - '2' + ('Z' - 'A') + 1; + } + s_fatal("Invalid base32 character"); +} + +static void +s_totp32(const char *secret, size_t len) +{ + if (!len) + return; + + char out[64]; + size_t outlen = 0; + unsigned buf = 0; + int bits = 0; + + for (int i = 0; i < len; i++) { + char c = secret[i]; + + if (!c || c == '=' || c == '\n') + break; + + buf = (buf << 5) | s_b32(c); + bits += 5; + + if (bits < 8) + continue; + + if (outlen == 64) + s_fatal("TOTP too big"); + + bits -= 8; + out[outlen++] = (buf >> bits) & 0xFF; + } + if (bits) + out[outlen++] = (buf << (8 - bits)) & 0xFF; + + s_totp(out, outlen); +} + static int s_show(int argc, char **argv, void *data) { @@ -535,7 +581,9 @@ s_show(int argc, char **argv, void *data) if (secret) { size_t len = load16_le(s.x.entry.slen); - if (strstr(argv[1], "totp")) { + if (strstr(argv[1], "totp32")) { + s_totp32(secret, len); + } else if (strstr(argv[1], "totp")) { s_totp(secret, len); } else { s_write(1, secret, len);