/* * otpcli - CLI utility for generating OTPs * * Written in 2020 by Lucas * * To the extent possible under law, the author(s) have dedicated all * copyright and related and neighboring rights to this software to the * public domain worldwide. This software is distributed without any * warranty. * * You should have received a copy of the CC0 Public Domain Dedication * along with this software. If not, see * . */ #include #include #include "otp.h" static int32_t otp(const EVP_MD *evp_md, const void *key, int key_len, uint64_t counter, unsigned int digits) { unsigned char md_value[EVP_MAX_MD_SIZE]; uint8_t buf[8]; uint32_t res; unsigned int md_len, modulo, offset; if (digits < 6 || digits > 10) return -1; for (modulo = 1000000; digits > 6; digits--, modulo *= 10) ; /* convert counter to big endian */ buf[0] = counter >> 56; buf[1] = (counter >> 48) & 0xff; buf[2] = (counter >> 40) & 0xff; buf[3] = (counter >> 32) & 0xff; buf[4] = (counter >> 24) & 0xff; buf[5] = (counter >> 16) & 0xff; buf[6] = (counter >> 8) & 0xff; buf[7] = counter & 0xff; 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; return (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; } 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 step, unsigned int digits) { return hotp(hmac, key, key_len, t / step, digits); }