【问题标题】:why my code doesn't generate the same OTP like google authenticator?为什么我的代码没有生成与谷歌身份验证器相同的 OTP?
【发布时间】:2022-01-14 22:45:09
【问题描述】:

有人知道为什么这个 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);
}

【问题讨论】:

    标签: c sha1 hmacsha1 google-authenticator totp


    【解决方案1】:

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

    您正在执行 strlen(counter)counter统一

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

    还有其他地方可以使用sizeof 而不是strlen。在下面的代码中,我更改了它们中的 all。这可能正确也可能不正确,因此您必须对其进行审查。


    这是一个重构版本:

    我使用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("%d\n", finalOTP);
    
        return 0;
    }
    

    【讨论】:

    • 我尝试了您的解决方案,但仍然无法生成正确的 OTP。我可以尝试使用 openssl 中的功能,但我不知道如何安装它...
    猜你喜欢
    • 1970-01-01
    • 2021-12-20
    • 2017-07-15
    • 2017-01-16
    • 2016-03-04
    • 2019-11-05
    • 2017-10-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多