Provide a single OTP function that accepts a configuration struct
This commit is contained in:
parent
44de0c64b0
commit
dd84a23e7e
23
cli.c
23
cli.c
@ -44,6 +44,7 @@ main(int argc, char *argv[])
|
|||||||
const char *errstr;
|
const char *errstr;
|
||||||
unsigned char *key;
|
unsigned char *key;
|
||||||
char *in, *line;
|
char *in, *line;
|
||||||
|
struct otpcfg otpcfg;
|
||||||
size_t inlen, linesz;
|
size_t inlen, linesz;
|
||||||
ssize_t linelen;
|
ssize_t linelen;
|
||||||
uint64_t counter;
|
uint64_t counter;
|
||||||
@ -132,17 +133,23 @@ main(int argc, char *argv[])
|
|||||||
if (!b32_decode(key, keylen, in, inlen))
|
if (!b32_decode(key, keylen, in, inlen))
|
||||||
errx(1, "error decoding base32 string");
|
errx(1, "error decoding base32 string");
|
||||||
|
|
||||||
|
otpcfg.algorithm = hmac;
|
||||||
|
otpcfg.digits = digits;
|
||||||
|
otpcfg.secret = key;
|
||||||
|
otpcfg.secretlen = keylen;
|
||||||
if (do_hotp) {
|
if (do_hotp) {
|
||||||
r = hotp(hmac, key, keylen, counter, digits);
|
otpcfg.type = OTP_HOTP;
|
||||||
if (r == -1)
|
otpcfg.u.hotp.counter = counter;
|
||||||
errx(1, "couldn't calculate HOTP");
|
|
||||||
printf("%0*" PRId32 "\n", digits, r);
|
|
||||||
} else {
|
} else {
|
||||||
r = totp(hmac, key, keylen, counter, period, digits);
|
otpcfg.type = OTP_TOTP;
|
||||||
if (r == -1)
|
otpcfg.u.totp.time = counter;
|
||||||
errx(1, "couldn't calculate TOTP");
|
otpcfg.u.totp.period = period;
|
||||||
printf("%0*" PRId32 "\n", digits, r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r = otp(&otpcfg);
|
||||||
|
if (r == -1)
|
||||||
|
errx(1, "couldn't calculate %cOTP", do_hotp ? 'H' : 'T');
|
||||||
|
printf("%0*" PRId32 "\n", digits, r);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
75
otp.c
75
otp.c
@ -18,19 +18,47 @@
|
|||||||
|
|
||||||
#include "otp.h"
|
#include "otp.h"
|
||||||
|
|
||||||
static int32_t
|
int32_t
|
||||||
otp(const EVP_MD *evp_md, const void *key, int key_len, uint64_t counter,
|
otp(const struct otpcfg *otpcfg)
|
||||||
unsigned int digits)
|
|
||||||
{
|
{
|
||||||
|
const EVP_MD *evp_md;
|
||||||
unsigned char md_value[EVP_MAX_MD_SIZE];
|
unsigned char md_value[EVP_MAX_MD_SIZE];
|
||||||
uint8_t buf[8];
|
uint8_t buf[8];
|
||||||
|
uint64_t counter;
|
||||||
uint32_t res;
|
uint32_t res;
|
||||||
int32_t modulo;
|
int32_t modulo;
|
||||||
unsigned int md_len, offset;
|
unsigned int digits, md_len, offset;
|
||||||
|
|
||||||
|
switch (otpcfg->type) {
|
||||||
|
case OTP_HOTP:
|
||||||
|
counter = otpcfg->u.hotp.counter;
|
||||||
|
break;
|
||||||
|
case OTP_TOTP:
|
||||||
|
if (otpcfg->u.totp.period == 0)
|
||||||
|
return -1;
|
||||||
|
counter = otpcfg->u.totp.time / otpcfg->u.totp.period;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (otpcfg->algorithm) {
|
||||||
|
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;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
digits = otpcfg->digits;
|
||||||
if (digits < 6 || digits > 10)
|
if (digits < 6 || digits > 10)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 10 digits would be 10_000_000_000, which overflows 32 bits.
|
* 10 digits would be 10_000_000_000, which overflows 32 bits.
|
||||||
* Nevertheless, given the number construction, 10 digits OTP are
|
* Nevertheless, given the number construction, 10 digits OTP are
|
||||||
@ -50,8 +78,8 @@ otp(const EVP_MD *evp_md, const void *key, int key_len, uint64_t counter,
|
|||||||
buf[6] = (counter >> 8) & 0xff;
|
buf[6] = (counter >> 8) & 0xff;
|
||||||
buf[7] = counter & 0xff;
|
buf[7] = counter & 0xff;
|
||||||
|
|
||||||
if (HMAC(evp_md, key, key_len, buf, sizeof(buf), md_value, &md_len) ==
|
if (HMAC(evp_md, otpcfg->secret, otpcfg->secretlen, buf, sizeof(buf),
|
||||||
NULL)
|
md_value, &md_len) == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
offset = md_value[md_len - 1] & 0xf;
|
offset = md_value[md_len - 1] & 0xf;
|
||||||
@ -63,36 +91,3 @@ otp(const EVP_MD *evp_md, const void *key, int key_len, uint64_t counter,
|
|||||||
|
|
||||||
return digits == 10 ? (int32_t)res : (int32_t)res % modulo;
|
return digits == 10 ? (int32_t)res : (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;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 period, unsigned int digits)
|
|
||||||
{
|
|
||||||
return hotp(hmac, key, key_len, t / period, digits);
|
|
||||||
}
|
|
||||||
|
27
otp.h
27
otp.h
@ -14,12 +14,33 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
enum otp_type {
|
||||||
|
OTP_HOTP,
|
||||||
|
OTP_TOTP,
|
||||||
|
};
|
||||||
|
|
||||||
enum otp_hmac {
|
enum otp_hmac {
|
||||||
OTP_HMAC_SHA1,
|
OTP_HMAC_SHA1,
|
||||||
OTP_HMAC_SHA256,
|
OTP_HMAC_SHA256,
|
||||||
OTP_HMAC_SHA512,
|
OTP_HMAC_SHA512,
|
||||||
};
|
};
|
||||||
|
|
||||||
int32_t hotp(enum otp_hmac, const void *, size_t, uint64_t, unsigned int);
|
struct otpcfg {
|
||||||
int32_t totp(enum otp_hmac, const void *, size_t, uint64_t, unsigned int,
|
enum otp_type type;
|
||||||
unsigned int);
|
enum otp_hmac algorithm;
|
||||||
|
unsigned int digits;
|
||||||
|
const void *secret;
|
||||||
|
size_t secretlen;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
uint64_t counter;
|
||||||
|
} hotp;
|
||||||
|
struct {
|
||||||
|
uint64_t time;
|
||||||
|
unsigned int period;
|
||||||
|
} totp;
|
||||||
|
} u;
|
||||||
|
};
|
||||||
|
|
||||||
|
int32_t otp(const struct otpcfg *);
|
||||||
|
Loading…
Reference in New Issue
Block a user