Skip to content

Instantly share code, notes, and snippets.

@hyc
Created June 9, 2015 12:31
Show Gist options
  • Select an option

  • Save hyc/4714dc33dfb698cf1e9c to your computer and use it in GitHub Desktop.

Select an option

Save hyc/4714dc33dfb698cf1e9c to your computer and use it in GitHub Desktop.
RFC6238 TOTP
/* RFC6238 TOTP */
#include <openssl/sha.h>
#include <openssl/hmac.h>
#define HMAC_setup(ctx, key, len, hash) HMAC_CTX_init(&ctx); HMAC_Init_ex(&ctx, key, len, hash, 0)
#define HMAC_crunch(ctx, buf, len) HMAC_Update(&ctx, buf, len)
#define HMAC_finish(ctx, dig, dlen) HMAC_Final(&ctx, dig, &dlen); HMAC_CTX_cleanup(&ctx)
typedef struct myval {
size_t my_size;
void *my_data;
} myval;
static void do_hmac(
const void *hash,
myval *key,
myval *data,
myval *out)
{
HMAC_CTX ctx;
unsigned int digestLen;
HMAC_setup(ctx, key->my_data, key->my_size, hash);
HMAC_crunch(ctx, data->my_data, data->my_size);
HMAC_finish(ctx, out->my_data, digestLen);
out->my_size = digestLen;
}
static const int DIGITS_POWER[] = {
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
static void generate(
myval *key,
unsigned long tval,
int digits,
myval *out,
const void *hash)
{
unsigned char digest[SHA512_DIGEST_LENGTH];
myval digval;
myval data;
unsigned char msg[8];
int i, offset, res, otp;
/* only needed on little-endian, can just use tval directly on big-endian */
for (i=7; i>=0; i--) {
msg[i] = tval & 0xff;
tval >>= 8;
}
data.my_data = msg;
data.my_size = sizeof(msg);
digval.my_data = digest;
digval.my_size = sizeof(digest);
do_hmac(hash, key, &data, &digval);
offset = digest[digval.my_size-1] & 0xf;
res = ((digest[offset] & 0x7f) << 24) |
((digest[offset+1] & 0xff) << 16) |
((digest[offset+2] & 0xff) << 8) |
(digest[offset+3] & 0xff);
otp = res % DIGITS_POWER[digits];
out->my_size = snprintf(out->my_data, out->my_size, "%0*d", digits, otp);
}
static void generateTOTP1(
myval *key,
long tval,
int digits,
myval *out)
{
generate(key, tval, digits, out, EVP_sha1());
}
static void generateTOTP256(
myval *key,
long tval,
int digits,
myval *out)
{
generate(key, tval, digits, out, EVP_sha256());
}
static void generateTOTP512(
myval *key,
long tval,
int digits,
myval *out)
{
generate(key, tval, digits, out, EVP_sha512());
}
#ifdef DO_TEST
int main() {
const char seed1[] = "12345678901234567890";
const char seed256[] = "12345678901234567890123456789012";
const char seed512[] = "1234567890123456789012345678901234567890123456789012345678901234";
char outbuf[32];
const long t0 = 0;
const long X = 30;
const long testTime[] = {59L, 1111111109L, 1111111111L, 1234567890L, 2000000000L, 20000000000L, 0};
int i;
myval key, data, out;
for (i=0; testTime[i]; i++) {
long t = (testTime[i] - t0)/X;
key.my_size = sizeof(seed1)-1;
key.my_data = seed1;
out.my_size = sizeof(outbuf);
out.my_data = outbuf;
generateTOTP1(&key, t, 8, &out);
printf("Time %ld, t %lx, SHA1 %s\n", testTime[i], t, out.my_data);
key.my_size = sizeof(seed256)-1;
key.my_data = seed256;
out.my_size = sizeof(outbuf);
out.my_data = outbuf;
generateTOTP256(&key, t, 8, &out);
printf("Time %ld, t %lx, SHA256 %s\n", testTime[i], t, out.my_data);
key.my_size = sizeof(seed512)-1;
key.my_data = seed512;
out.my_size = sizeof(outbuf);
out.my_data = outbuf;
generateTOTP512(&key, t, 8, &out);
printf("Time %ld, t %lx, SHA512 %s\n", testTime[i], t, out.my_data);
}
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment