From dd84a23e7e33c4d988278326d941bc0230b4253d Mon Sep 17 00:00:00 2001 From: Lucas Date: Tue, 16 Feb 2021 16:59:56 +0000 Subject: [PATCH] Provide a single OTP function that accepts a configuration struct --- cli.c | 23 +++++++++++------- otp.c | 75 ++++++++++++++++++++++++++++------------------------------- otp.h | 27 ++++++++++++++++++--- 3 files changed, 74 insertions(+), 51 deletions(-) diff --git a/cli.c b/cli.c index 86790c4..a367457 100644 --- a/cli.c +++ b/cli.c @@ -44,6 +44,7 @@ main(int argc, char *argv[]) const char *errstr; unsigned char *key; char *in, *line; + struct otpcfg otpcfg; size_t inlen, linesz; ssize_t linelen; uint64_t counter; @@ -132,17 +133,23 @@ main(int argc, char *argv[]) if (!b32_decode(key, keylen, in, inlen)) errx(1, "error decoding base32 string"); + otpcfg.algorithm = hmac; + otpcfg.digits = digits; + otpcfg.secret = key; + otpcfg.secretlen = keylen; if (do_hotp) { - r = hotp(hmac, key, keylen, counter, digits); - if (r == -1) - errx(1, "couldn't calculate HOTP"); - printf("%0*" PRId32 "\n", digits, r); + otpcfg.type = OTP_HOTP; + otpcfg.u.hotp.counter = counter; } else { - r = totp(hmac, key, keylen, counter, period, digits); - if (r == -1) - errx(1, "couldn't calculate TOTP"); - printf("%0*" PRId32 "\n", digits, r); + otpcfg.type = OTP_TOTP; + otpcfg.u.totp.time = counter; + otpcfg.u.totp.period = period; } + r = otp(&otpcfg); + if (r == -1) + errx(1, "couldn't calculate %cOTP", do_hotp ? 'H' : 'T'); + printf("%0*" PRId32 "\n", digits, r); + return 0; } diff --git a/otp.c b/otp.c index f63eb39..b122cfa 100644 --- a/otp.c +++ b/otp.c @@ -18,19 +18,47 @@ #include "otp.h" -static int32_t -otp(const EVP_MD *evp_md, const void *key, int key_len, uint64_t counter, - unsigned int digits) +int32_t +otp(const struct otpcfg *otpcfg) { + const EVP_MD *evp_md; unsigned char md_value[EVP_MAX_MD_SIZE]; uint8_t buf[8]; + uint64_t counter; uint32_t res; int32_t modulo; - unsigned int md_len, offset; + unsigned int digits, md_len, offset; + switch (otpcfg->type) { + case OTP_HOTP: + counter = otpcfg->u.hotp.counter; + break; + case OTP_TOTP: + if (otpcfg->u.totp.period == 0) + return -1; + counter = otpcfg->u.totp.time / otpcfg->u.totp.period; + break; + default: + return -1; + } + + switch (otpcfg->algorithm) { + case OTP_HMAC_SHA1: + evp_md = EVP_sha1(); + break; + case OTP_HMAC_SHA256: + evp_md = EVP_sha256(); + break; + case OTP_HMAC_SHA512: + evp_md = EVP_sha512(); + break; + default: + return -1; + } + + digits = otpcfg->digits; if (digits < 6 || digits > 10) return -1; - /* * 10 digits would be 10_000_000_000, which overflows 32 bits. * Nevertheless, given the number construction, 10 digits OTP are @@ -50,8 +78,8 @@ otp(const EVP_MD *evp_md, const void *key, int key_len, uint64_t counter, buf[6] = (counter >> 8) & 0xff; buf[7] = counter & 0xff; - if (HMAC(evp_md, key, key_len, buf, sizeof(buf), md_value, &md_len) == - NULL) + if (HMAC(evp_md, otpcfg->secret, otpcfg->secretlen, buf, sizeof(buf), + md_value, &md_len) == NULL) return -1; offset = md_value[md_len - 1] & 0xf; @@ -63,36 +91,3 @@ otp(const EVP_MD *evp_md, const void *key, int key_len, uint64_t counter, return digits == 10 ? (int32_t)res : (int32_t)res % modulo; } - -int32_t -hotp(enum otp_hmac hmac, const void *key, size_t key_len, uint64_t counter, - unsigned int digits) -{ - const EVP_MD *evp_md; - - if (key_len > INT_MAX) - return -1; - - switch (hmac) { - case OTP_HMAC_SHA1: - evp_md = EVP_sha1(); - break; - case OTP_HMAC_SHA256: - evp_md = EVP_sha256(); - break; - case OTP_HMAC_SHA512: - evp_md = EVP_sha512(); - break; - default: - return -1; - } - - return otp(evp_md, key, (int)key_len, counter, digits); -} - -int32_t -totp(enum otp_hmac hmac, const void *key, size_t key_len, uint64_t t, - unsigned int period, unsigned int digits) -{ - return hotp(hmac, key, key_len, t / period, digits); -} diff --git a/otp.h b/otp.h index 9334b5e..5b55fc1 100644 --- a/otp.h +++ b/otp.h @@ -14,12 +14,33 @@ #include +enum otp_type { + OTP_HOTP, + OTP_TOTP, +}; + enum otp_hmac { OTP_HMAC_SHA1, OTP_HMAC_SHA256, OTP_HMAC_SHA512, }; -int32_t hotp(enum otp_hmac, const void *, size_t, uint64_t, unsigned int); -int32_t totp(enum otp_hmac, const void *, size_t, uint64_t, unsigned int, - unsigned int); +struct otpcfg { + enum otp_type type; + enum otp_hmac algorithm; + unsigned int digits; + const void *secret; + size_t secretlen; + + union { + struct { + uint64_t counter; + } hotp; + struct { + uint64_t time; + unsigned int period; + } totp; + } u; +}; + +int32_t otp(const struct otpcfg *);