c语言 - 为什么我的代码没有像谷歌身份验证器那样生成相同的 OTP?



有人知道为什么这个TOTP代码不能像谷歌验证器一样生成相同的OTP???SHA1-HASH函数运行良好,只是生成的最后一个OTP不正确。我试着检查所有的东西,但我找不到我的错误在哪里。有人能帮忙吗?这个代码应该是生成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;
}

已编辑


我的SHA_1代码:

#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);
}

您有一些UB(未定义的行为(。

您正在执行strlen(counter),但counter单元化

而且,对于加密货币,您可能想要sizeof(counter),就像您在其他地方所做的那样。

还有其他地方可以使用sizeof而不是strlen。在下面的代码中,我更改了所有。这可能是正确的,也可能不是正确的,所以你必须复习一下。


这里有一个重构版本:

我使用了cpp条件词来表示新旧代码:

#if 0
// old code
#else
// new code
#endif

这是代码。我无法访问您版本的SHA1代码,所以我使用了openssl。如果您使用它,请将代码与-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("%dn", finalOTP);
return 0;
}

最新更新