不同的SHA-256哈希值取决于输入是用sizeof还是strlen测量的

时间:2016-06-21 12:47:35

标签: c string hash

我正在编写一个程序来计算从stdin读取的字符串的SHA-256。 我正在使用openssl/sha.h提供的功能进入我的程序。我实现了#34;普通哈希"和#34;盐渍哈希"。

正常哈希

如果我对单词password进行哈希,我会得到以下输出:

SHA256_Update(&sha256, string, strlen(string)) --> 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8
SHA256_Update(&sha256, string, sizeof(string)) --> 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8

这是正确的,如shell命令

的输出所示
echo -n "password" | sha256sum --> 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8

咸味哈希

然后我尝试实现 salted hash ,将输入字符串连接到另一个字符串(salt)之后,获取

complete = salt + string

鉴于salt总是相同的(26000,计算为13 * 2000),我期望输出匹配shell命令:

echo -n "26000password" | sha256sum --> c9bcf6ab867bdff7bf2223407c6a391f5c475fb411f7eae08fb361a671d4fd0d

使用strlen(complete)给出正确答案:

SHA256_Update(&sha256, complete, strlen(complete)) --> c9bcf6ab867bdff7bf2223407c6a391f5c475fb411f7eae08fb361a671d4fd0d

然而,使用sizeof(complete)给出了不同的答案:

SHA256_Update(&sha256, complete, sizeof(complete)) --> ef73eaf729a0601f9d99ed0a11ef82ae82ca74042de5a724889f82e4f6e59bb0

所以我有两个问题:

  1. 第二种情况有问题(我认为是使用sizeof代替strlen,但这并不能解释为什么我遇到第二个问题,所以我是考虑一些"记忆的不一致状态");
  2. 如果我再次执行程序,每次停止并执行程序时,错误的哈希都会不断变化。
  3. 所以我认为问题在于使用sizeof而不是strlen。我知道sizeof返回用于存储该数据类型的字节数(因此指针将是4个字节),而strlen将给出字符串的长度,但我不知道'}我明白为什么我只在第二种情况下得到错误。

    代码摘录

    #include <openssl/sha.h>
    #define MAX_LENGTH 1024
    
    unsigned long salt;
    
    // Salted ////////////////////////////////
    void compute_sha256_with_sizeof_complete(const char *string, char *sha)
    {
        int i;
        char temp[65];
        char complete[MAX_LENGTH];
        char salt_str[MAX_LENGTH];
        unsigned char hash[SHA256_DIGEST_LENGTH];  
        SHA256_CTX sha256;
    
        /* complete = salt_str + string */
        if (sprintf(salt_str, "%lu", salt) < 0)
            error_handler("compute_sha256 | sprintf");
        if (strcpy(complete, salt_str) == NULL)
            error_handler("compute_sha256 | strcpy");
        if (strcat(complete, string) == NULL)
            error_handler("compute_sha256 | strcat");
    
        /* compute sha256 of 'complete' */
        if (SHA256_Init(&sha256) == 0)
            error_handler("compute_sha256 | SHA256_Init");
        if (SHA256_Update(&sha256, complete, sizeof(complete)) == 0)
            error_handler("compute_sha256 | SHA256_Update");
        if (SHA256_Final(hash, &sha256) == 0)
            error_handler("compute_sha256 | SHA256_Final");
        for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
            if ((sprintf(temp + (i * 2), "%02x", hash[i])) < 0)
                error_handler("compute_sha256 | sprintf");
    
        temp[64] = 0;
    
        if (strcpy(sha, temp) == NULL)
            error_handler("compute_sha256 | strcpy");
    
        printf("SHA256 (sizeof_complete):\t%s\n", sha);
    }
    
    void compute_sha256_with_strlen_complete(const char *string, char *sha)
    {
        int i;
        char temp[65];
        char complete[MAX_LENGTH];
        char salt_str[MAX_LENGTH];
        unsigned char hash[SHA256_DIGEST_LENGTH];  
        SHA256_CTX sha256;
    
        /* complete = salt_str + string */
        if (sprintf(salt_str, "%lu", salt) < 0)
            error_handler("compute_sha256 | sprintf");
        if (strcpy(complete, salt_str) == NULL)
            error_handler("compute_sha256 | strcpy");
        if (strcat(complete, string) == NULL)
            error_handler("compute_sha256 | strcat");
    
        /* compute sha256 of 'complete' */
        if (SHA256_Init(&sha256) == 0)
            error_handler("compute_sha256 | SHA256_Init");
        if (SHA256_Update(&sha256, complete, strlen(complete)) == 0)
            error_handler("compute_sha256 | SHA256_Update");
        if (SHA256_Final(hash, &sha256) == 0)
            error_handler("compute_sha256 | SHA256_Final");
        for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
            if ((sprintf(temp + (i * 2), "%02x", hash[i])) < 0)
                error_handler("compute_sha256 | sprintf");
    
        temp[64] = 0;
    
        if (strcpy(sha, temp) == NULL)
            error_handler("compute_sha256 | strcpy");
    
        printf("SHA256 (strlen_complete):\t%s\n", sha);
    }
    
    // Normal ////////////////////////////////
    
    void compute_sha256_with_sizeof_string(const char *string, char *sha)
    {
        int i;
        char temp[65];
        char complete[MAX_LENGTH];
        char salt_str[MAX_LENGTH];
        unsigned char hash[SHA256_DIGEST_LENGTH];  
        SHA256_CTX sha256;
    
        /* complete = salt_str + string */
        if (sprintf(salt_str, "%lu", salt) < 0)
            error_handler("compute_sha256 | sprintf");
        if (strcpy(complete, salt_str) == NULL)
            error_handler("compute_sha256 | strcpy");
        if (strcat(complete, string) == NULL)
            error_handler("compute_sha256 | strcat");
    
        /* compute sha256 of 'string' */
        if (SHA256_Init(&sha256) == 0)
            error_handler("compute_sha256 | SHA256_Init");
        if (SHA256_Update(&sha256, string, sizeof(string)) == 0)
            error_handler("compute_sha256 | SHA256_Update");
        if (SHA256_Final(hash, &sha256) == 0)
            error_handler("compute_sha256 | SHA256_Final");
        for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
            if ((sprintf(temp + (i * 2), "%02x", hash[i])) < 0)
                error_handler("compute_sha256 | sprintf");
    
        temp[64] = 0;
    
        if (strcpy(sha, temp) == NULL)
            error_handler("compute_sha256 | strcpy");
    
        printf("SHA256 (sizeof_string):\t\t%s\n", sha);
    }
    
    void compute_sha256_with_strlen_string(const char *string, char *sha)
    {
        int i;
        char temp[65];
        char complete[MAX_LENGTH];
        char salt_str[MAX_LENGTH];
        unsigned char hash[SHA256_DIGEST_LENGTH];  
        SHA256_CTX sha256;
    
        /* complete = salt_str + string */
        if (sprintf(salt_str, "%lu", salt) < 0)
            error_handler("compute_sha256 | sprintf");
        if (strcpy(complete, salt_str) == NULL)
            error_handler("compute_sha256 | strcpy");
        if (strcat(complete, string) == NULL)
            error_handler("compute_sha256 | strcat");
    
        /* compute sha256 of 'string' */
        if (SHA256_Init(&sha256) == 0)
            error_handler("compute_sha256 | SHA256_Init");
        if (SHA256_Update(&sha256, string, strlen(string)) == 0)
            error_handler("compute_sha256 | SHA256_Update");
        if (SHA256_Final(hash, &sha256) == 0)
            error_handler("compute_sha256 | SHA256_Final");
        for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
            if ((sprintf(temp + (i * 2), "%02x", hash[i])) < 0)
                error_handler("compute_sha256 | sprintf");
    
        temp[64] = 0;
    
        if (strcpy(sha, temp) == NULL)
            error_handler("compute_sha256 | strcpy");
    
        printf("SHA256 (strlen_string):\t\t%s\n", sha);
    }
    
    void match_password(const char *line)
    {
        char hash[MAX_LENGTH];
        salt *= 13;
    
        compute_sha256_with_strlen_complete(line, hash);
        compute_sha256_with_sizeof_complete(line, hash);
        compute_sha256_with_strlen_string(line, hash);
        compute_sha256_with_sizeof_string(line, hash);
    }
    
    void read_password_from_stdin(void)
    {
        char line[MAX_LENGTH];
        salt = 2000;
    
        printf("> ");
    
        if (fgets(line, MAX_LENGTH, stdin) == NULL)
            error_handler("read_password_from_stdin | fgets");
        if (line[strlen(line)-1] == '\n')
            line[strlen(line)-1] = '\0';
    
        match_password(line);
    }
    
    int main(int argc, char **argv)
    {
        if (argc != 1)
        {
            fprintf(stderr, "Usage: %s <no arguments>\n", argv[0]);
            return EXIT_FAILURE;
        }
    
        while (!feof(stdin))
            read_password_from_stdin();
    
        return EXIT_SUCCESS;
    }
    

2 个答案:

答案 0 :(得分:1)

使用sizeof,您可以在complete的每个八位字节上计算sha(即<{1}}八位字节上的),而只是在有用的八位字节上计算。

MAX_LENGTH未初始化,因此内容可以是任何内容,每次发布时都不同。使用completesprintfstrcat仅初始化包含字符串的部分,因此数组的结尾仍然未初始化。要每次都使用相同的哈希值,请初始化strcpy

complete

答案 1 :(得分:0)

sizeof(complete)始终为MAX_LENGTH或1024.在compute_sha256_with_sizeof_complete中,completesalt_str是局部变量,因此在堆栈上分配,可能有函数开始运行时的任何内容,具体取决于编译器。我猜想complete中至少有一些非零值,strcpystrcat除非是盐字符串,或者你从{{1}读取的内容,否则不会替换这些值},字符长stdin。因此,您不仅要获取所放入数据的SHA-256,还要获取MAX_LENGTH开始运行时complete中随机数据的所有数据。

这也是每次compute_sha256_with_sizeof_complete输出更改的原因:每次程序运行时,堆栈中留下的随机数据(因此在sizeof_complete中)可能会有所不同。要明确初始化它,您可以说complete,但最好不要在这种情况下使用char complete[MAX_LENGTH] = {0}; :)。

相比之下,使用sizeof仅对字符串内容进行哈希处理,直至终止NULL字符。 strlenstrcpy按预期填充字符串的那一部分,这就是您获得预期结果的原因。 strcat绝对是正确的选择。 (在进行编码时,请使用strlenstrncpy代替strncatstrcpy added protection against memory issues。)