diff --git a/Makefile b/Makefile index 8d09720..55079d6 100644 --- a/Makefile +++ b/Makefile @@ -17,8 +17,8 @@ P = otpcli V = 0.0 -HDR = err.h -OBJ = cli.o err.o +HDR = err.h otp.h +OBJ = cli.o err.o otp.o SRC = ${OBJ:.o=.c} DIST_FILES = COPYING Makefile ${HDR} ${SRC} diff --git a/otp.c b/otp.c new file mode 100644 index 0000000..87c3b0c --- /dev/null +++ b/otp.c @@ -0,0 +1,82 @@ +/* + * 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, time_t t, + unsigned int granularity, unsigned int digits) +{ + return -1; +} diff --git a/otp.h b/otp.h new file mode 100644 index 0000000..812009e --- /dev/null +++ b/otp.h @@ -0,0 +1,27 @@ +/* + * 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 + +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, time_t, unsigned int, + unsigned int);