/* * otpcli - CLI utility for generating OTPs * * Written in 2020-2021 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 #include #include #include #include #include #include "err.h" #include "strtonum.h" #include "otp.h" #define LINE_SIZE 16384 extern const char *__progname; static void usage(void) { fprintf(stderr, "Usage:\n" " %s [-d digits] [-h HMAC] -H counter SECRET\n" " %s [-d digits] [-h HMAC] [-s step] [-T counter] SECRET\n", __progname, __progname); exit(1); } int main(int argc, char *argv[]) { const char *errstr; char *key; size_t key_len; uint64_t counter; unsigned int step; int32_t r; int ch, digits, do_hotp, do_totp; enum otp_hmac hmac; counter = (uint64_t)time(NULL); digits = 6; do_hotp = do_totp = 0; hmac = OTP_HMAC_SHA1; step = 30; while ((ch = getopt(argc, argv, "d:H:h:s:T:")) != -1) { switch (ch) { case 'd': digits = strtonum(optarg, 6, 10, &errstr); if (errstr != NULL) errx(1, "digits is %s: %s", errstr, optarg); break; case 'H': counter = strtonum(optarg, 0, LLONG_MAX, &errstr); if (errstr != NULL) errx(1, "counter is %s: %s", errstr, optarg); do_hotp = 1; break; case 'h': if (strcasecmp(optarg, "sha1") == 0) hmac = OTP_HMAC_SHA1; else if (strcasecmp(optarg, "sha256") == 0) hmac = OTP_HMAC_SHA256; else if (strcasecmp(optarg, "sha512") == 0) hmac = OTP_HMAC_SHA512; else usage(); break; case 's': step = strtonum(optarg, 1, UINT_MAX, &errstr); if (errstr != NULL) errx(1, "step is %s: %s", errstr, optarg); break; case 'T': counter = strtonum(optarg, 0, LLONG_MAX, &errstr); if (errstr != NULL) errx(1, "counter is %s: %s", errstr, optarg); do_totp = 1; break; default: usage(); } } argc -= optind; argv += optind; if (do_hotp && do_totp) { warnx("-H and -T are mutually exclusive"); usage(); } if (argc > 1) usage(); if (argc == 1) { key = argv[0]; key_len = strlen(key); } else { key = malloc(sizeof(uint8_t) * (LINE_SIZE + 1)); if (key == NULL) err(1, "malloc"); if (fgets(key, LINE_SIZE + 1, stdin) == NULL) err(1, "fgets"); key_len = strlen(key); if (key[key_len - 1] == '\n') { key[key_len - 1] = '\0'; key_len--; } } if (do_hotp) { r = hotp(hmac, key, key_len, counter, digits); if (r == -1) errx(1, "couldn't calculate HOTP"); printf("%0*" PRId32 "\n", digits, r); } else { r = totp(hmac, key, key_len, counter, step, digits); if (r == -1) errx(1, "couldn't calculate TOTP"); printf("%0*" PRId32 "\n", digits, r); } return 0; }