someone know why this TOTP code doesn't generate the same OTP like google authenticator??? the SHA1-HASH function is working well, it's just the final OTP that dosen't generated correct. I tried to check everything and I couldn't find where my mistake. can someone help please? this code supposed to be a very basic code to generate TOTP.
#include <stdio.h>
#include <math.h>
#include <time.h>
#include "SHA_1.h"
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);
for (i = strlen(counter)-1; i >= 0; i--)
{
counter[i] = (unsigned char)(CT & 0xFF);
CT >>= 8;
}
// HMAC
// Inner Key = K xor 0x36
memset(inner_key, 0, 64);
memcpy(inner_key, secretKey, strlen(secretKey));
xor(inner_key, sizeof(inner_key), i_pad);
// Outter Key = K xor 0x5C
memset(outter_key, 0, 64);
memcpy(outter_key, secretKey, strlen(secretKey));
xor(outter_key, sizeof(outter_key), o_pad);
// Hash Inner
memset(block, 0, sizeof(block));
for (i = 0; i < 64; i++)
{
block[i] = inner_key[i];
}
for (i = 0; i < strlen(counter); i++)
{
block[i + 64] = counter[i];
}
SHA1_HASH(block, strlen(block), result);
// Hash Outter
memset(block, 0, sizeof(block));
for (i = 0; i < 64; i++)
{
block[i] = outter_key[i];
}
for (i = 0; i < strlen(result); i++)
{
block[i + 64] = result[i];
}
SHA1_HASH(block, strlen(block), result);
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", finalOTP);
return 0;
}
EDITED
My SHA_1 code:
#include <stdio.h>
#include <string.h>
// circular rotate function
unsigned int S(int n, unsigned int word)
{
return ((word << n) | (word >> (32 - n)));
}
// constant K
const unsigned int K[4] = {
0x5A827999,
0x6ED9EBA1,
0x8F1BBCDC,
0xCA62C1D6};
// H values
unsigned int H[5] = {
0x67452301,
0xEFCDAB89,
0x98BADCFE,
0x10325476,
0xC3D2E1F0};
void SHA1_HASH(unsigned char *input,int input_length, char *output)
{
// Variabels Declaration
unsigned char M[128];
unsigned int W[80];
unsigned int j, i, TEMP, A, B, C, D, E;
unsigned char HH[20], temp_HH[20];
int M_size;
// clear M
memset(M, 0, sizeof(M));
// Copy the messege into M
strcpy(M, input);
// add the length of the messege to the end of M
if (input_length > 55)
{
M[127] = (unsigned char)(input_length * 8);
M[126] = (unsigned char)(input_length * 8 >> 8);
M_size = 2;
}
else
{
M[63] = (unsigned char)(input_length * 8);
M[62] = (unsigned char)(input_length * 8 >> 8);
M_size = 1;
}
// set bit '1' after the messege
M[input_length] |= (unsigned char)0x80;
for(j=0; j<M_size; j++){
//init Words in W[0] - W[15]
for (i = 0; i < 16; i++)
{
W[i] = ((unsigned int)M[(4 * i)+(64*j)] << 24) | ((unsigned int)M[(1 + (4 * i))+(64*j)] << 16) | ((unsigned int)M[(2 + (4 * i))+(64*j)] << 8) | ((unsigned int)M[(3 + (4 * i))+(64*j)]);
}
for (i = 16; i < 80; i++)
{
W[i] = S(1, W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]);
}
//start of the SHA-1 alghoritem
A = H[0];
B = H[1];
C = H[2];
D = H[3];
E = H[4];
for (i = 0; i < 20; i++) // round 1
{
TEMP = S(5, A) + ((B & C) | ((~B) & D)) + E + W[i] + K[0];
E = D;
D = C;
C = S(30, B);
B = A;
A = TEMP;
}
for (i = 20; i < 40; i++) //round 2
{
TEMP = S(5, A) + (B ^ C ^ D) + E + W[i] + K[1];
E = D;
D = C;
C = S(30, B);
B = A;
A = TEMP;
}
for (i = 40; i < 60; i++) //round 3
{
TEMP = S(5, A) + ((B & C) | (B & D) | (C & D)) + E + W[i] + K[2];
E = D;
D = C;
C = S(30, B);
B = A;
A = TEMP;
}
for (i = 60; i < 80; i++) //round 4
{
TEMP = S(5, A) + (B ^ C ^ D) + E + W[i] + K[3];
E = D;
D = C;
C = S(30, B);
B = A;
A = TEMP;
}
H[0] += A;
H[1] += B;
H[2] += C;
H[3] += D;
H[4] += E;
}
sprintf(HH, "%x", H[0]);
for (i = 1; i < 5; i++)
{
sprintf(temp_HH, "%x", H[i]);
strcat(HH, temp_HH);
}
// end of SHA-1 alghoritem
// return the algoritem result
strcpy(output, HH);
}
You have some UB (undefined behavior).
You're doing
strlen(counter)butcounteris unitialized.And, for crypto, you probably want
sizeof(counter)as you've done in other places.There are other places to use
sizeofinstead ofstrlen. 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
cppconditionals to denote old vs new code: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: