From 4d2024128ee7c79aadeb35c0e63593db15b16f31 Mon Sep 17 00:00:00 2001 From: Lucas Date: Thu, 11 Feb 2021 21:20:06 +0000 Subject: [PATCH] Fix an overflow for 10-digits OTP --- otp.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/otp.c b/otp.c index aa7f1ff..021803b 100644 --- a/otp.c +++ b/otp.c @@ -26,12 +26,20 @@ otp(const EVP_MD *evp_md, const void *key, int key_len, uint64_t counter, unsigned char md_value[EVP_MAX_MD_SIZE]; uint8_t buf[8]; uint32_t res; - unsigned int md_len, modulo, offset; + int32_t modulo; + unsigned int md_len, offset; if (digits < 6 || digits > 10) return -1; - for (modulo = 1000000; digits > 6; digits--, modulo *= 10) - ; + + /* + * 10 digits would be 10_000_000_000, which overflows 32 bits. + * Nevertheless, given the number construction, 10 digits OTP are + * possible. We won't apply reminder operator in that case. + */ + if (digits < 10) + for (modulo = 1000000; digits > 6; digits--, modulo *= 10) + continue; /* convert counter to big endian */ buf[0] = counter >> 56; @@ -46,14 +54,15 @@ otp(const EVP_MD *evp_md, const void *key, int key_len, uint64_t counter, if (HMAC(evp_md, key, key_len, buf, sizeof(buf), md_value, &md_len) == NULL) return -1; + offset = md_value[md_len - 1] & 0xf; res = (md_value[offset] << 24) | (md_value[offset + 1] << 16) | (md_value[offset + 2] << 8) | md_value[offset + 3]; - res &= ~0x80000000; + res &= 0x7fffffff; - return (int32_t)res % modulo; + return digits == 10 ? (int32_t)res : (int32_t)res % modulo; } int32_t