why my code doesn't generate the same OTP like google authenticator?
You have some UB (undefined behavior).
You're doing strlen(counter)
but counter
is unitialized.
And, for crypto, you probably want sizeof(counter)
as you've done in other places.
There are other places to use sizeof
instead of strlen
. In the code below, I changed all of them. That may or may not be correct, so you'll have to review that.
Here's a refactored version:
I've used cpp
conditionals to denote old vs new code:
#if 0
// old code
#else
// new code
#endif
Here is the code. I didn't have access to your version of the SHA1 code, so I used openssl
. If you use that, link the code with -lssl -lcrypto
:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <time.h>
#if 0
#include "SHA_1.h"
#else
#include <openssl/sha.h>
void
SHA1_HASH(const unsigned char *buf,size_t len,unsigned char *result)
{
SHA_CTX ctx;
SHA1_Init(&ctx);
SHA1_Update(&ctx,buf,len);
SHA1_Final(result,&ctx);
}
#endif
void
xor(char *arr, int length, int value)
{
int i;
for (i = 0; i < length; i++)
arr[i] ^= value;
}
int
main()
{
int CT, i, j;
long int T;
const int T0 = 0,
Tx = 30;
const char o_pad = 0x5C,
i_pad = 0x36;
unsigned char result[20];
unsigned char counter[8];
unsigned char secretKey[64] = "abcdefghijklmnop";
// HMAC
unsigned char block[128];
unsigned char inner_key[64];
unsigned char outter_key[64];
// HOTP
int offset;
long int truncatedHash;
long int finalOTP;
T = (long int) (time(NULL));
CT = floor((T - T0) / Tx);
#if 0
for (i = strlen(counter) - 1; i >= 0; i--) {
#else
for (i = sizeof(counter) - 1; i >= 0; i--) {
#endif
counter[i] = (unsigned char) (CT & 0xFF);
CT >>= 8;
}
// HMAC
// Inner Key = K xor 0x36
#if 0
memset(inner_key, 0, 64);
memcpy(inner_key, secretKey, strlen(secretKey));
#else
memset(inner_key, 0, sizeof(inner_key));
strcpy(inner_key, secretKey);
#endif
xor(inner_key, sizeof(inner_key), i_pad);
// Outter Key = K xor 0x5C
#if 0
memset(outter_key, 0, 64);
memcpy(outter_key, secretKey, strlen(secretKey));
#else
memset(outter_key, 0, sizeof(outter_key));
strcpy(outter_key, secretKey);
#endif
xor(outter_key, sizeof(outter_key), o_pad);
// Hash Inner
memset(block, 0, sizeof(block));
#if 0
for (i = 0; i < 64; i++) {
block[i] = inner_key[i];
}
#else
for (i = 0; i < sizeof(inner_key); i++) {
block[i] = inner_key[i];
}
#endif
#if 0
for (i = 0; i < strlen(counter); i++) {
block[i + 64] = counter[i];
}
#else
for (i = 0; i < sizeof(counter); i++) {
block[i + sizeof(inner_key)] = counter[i];
}
#endif
#if 0
SHA1_HASH(block, strlen(block), result);
#else
SHA1_HASH(block, sizeof(block), result);
#endif
// Hash Outter
memset(block, 0, sizeof(block));
#if 0
for (i = 0; i < 64; i++) {
block[i] = outter_key[i];
}
#else
for (i = 0; i < sizeof(outter_key); i++) {
block[i] = outter_key[i];
}
#endif
#if 0
for (i = 0; i < strlen(result); i++) {
block[i + 64] = result[i];
}
#else
for (i = 0; i < sizeof(result); i++) {
block[i + sizeof(outter_key)] = result[i];
}
#endif
#if 0
SHA1_HASH(block, strlen(block), result);
#else
SHA1_HASH(block, sizeof(block), result);
#endif
offset = result[19] & 0x0f;
truncatedHash = ((result[offset] & 0x7f) << 24) |
((result[offset + 1] & 0xff) << 16) |
((result[offset + 2] & 0xff) << 8) |
(result[offset + 3] & 0xff);
finalOTP = (truncatedHash % (long int) pow(10, 6));
printf("%d\n", finalOTP);
return 0;
}