// otp.c, version 0.2.0 // OMKOV cryptutils otp // Copyright (C) 2020, Jakob Wakeling // MIT Licence #include "util/base32.h" #include "util/error.c" #include "util/optget.h" #include "util/strconv.h" #include #include #include #include #include #define VERSION "0.2.0" static struct lop lops[] = { { "help", ARG_NUL, 256 }, { "version", ARG_NUL, 257 }, { NULL, 0, 0 } }; static inline uint32_t hotp(uint8_t *K, size_t Klen, uint64_t C); static void hlp(void); static void ver(void); int main(int ac, char *av[]) { A0 = av[0]; struct opt opt = OPTGET_INIT; opt.str = ""; opt.lops = lops; for (int o; (o = optget(&opt, av, 1)) != -1;) switch (o) { case 256: { hlp(); return 0; } case 257: { ver(); return 0; } default: { return 1; } } if (opt.ind == ac) { error(1, "missing operand"); } uint8_t *k; size_t l = strlen(av[opt.ind]); uint64_t c; if (opt.ind == ac - 1) { c = time(NULL) / 30; } else { char *ep; c = strtou64(av[opt.ind + 1], &ep, 10); if (*ep) { error(1, "invalid counter"); } } k = (uint8_t *)malloc(B32DLEN(l) * sizeof (*k)); if (!k) { error(1, "%s", serr()); } size_t kl = b32decode(k, (uint8_t *)av[opt.ind], l); printf("%06u\n", hotp(k, kl, c)); free(k); return 0; } /* Compute HOTP token with a key and counter */ static inline uint32_t hotp(uint8_t *K, size_t Klen, uint64_t C) { // Convert the counter to big endian if it isn't already uint32_t e = 0x000000FF; if ((*(uint8_t *)&e) == 0xFF) { C = ((C & 0x00000000FFFFFFFF) << 32) | ((C & 0xFFFFFFFF00000000) >> 32); C = ((C & 0x0000FFFF0000FFFF) << 16) | ((C & 0xFFFF0000FFFF0000) >> 16); C = ((C & 0x00FF00FF00FF00FF) << 8) | ((C & 0xFF00FF00FF00FF00) >> 8); } // Step 1: Generate HMAC-SHA-1 digest uint8_t *d = HMAC(EVP_sha1(), K, Klen, (uint8_t *)&C, sizeof (C), NULL, 0); // Step 2: Truncate digest to 4 bytes uint32_t dt = (d[(d[19] & 0x0F)] & 0x7F) << 24 | (d[(d[19] & 0x0F) + 1] & 0xFF) << 16 | (d[(d[19] & 0x0F) + 2] & 0xFF) << 8 | (d[(d[19] & 0x0F) + 3] & 0xFF); // Step 3: Calculate modulus of dt to get HOTP token return dt % (uint32_t)pow(10, 6/*Token length*/); } /* Print help information */ static void hlp(void) { puts("otp - compute hotp or totp tokens\n"); puts("usage: otp secret [counter]\n"); puts("options:"); puts(" --help Display help information"); puts(" --version Display version information"); } /* Print version information */ static void ver(void) { puts("OMKOV cryptutils otp, version " VERSION); puts("Copyright (C) 2020, Jakob Wakeling"); puts("MIT Licence (https://opensource.org/licenses/MIT)"); }