Created
June 9, 2015 12:31
-
-
Save hyc/4714dc33dfb698cf1e9c to your computer and use it in GitHub Desktop.
RFC6238 TOTP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* 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