【问题标题】:MD5 of string gives wrong output in C字符串的 MD5 在 C 中给出错误的输出
【发布时间】:2019-02-19 18:06:36
【问题描述】:

我的问题类似于this one here,但我使用的是 openssl/md5.h

我正在尝试获取用户输入并找到其 MD5 哈希值。这是我的代码:

#include <stdio.h>
#include <openssl/md5.h>
#include <stdlib.h>
#include <string.h>

void MD5hash(unsigned char *data, unsigned int dataLen, unsigned char *digest) {
    MD5_CTX c;
    MD5_Init(&c);
    MD5_Update(&c, data, dataLen);
    MD5_Final(digest, &c);
}

int main(){
    unsigned char md5_hash[MD5_DIGEST_LENGTH];
    char *input = NULL;
    int i, read;
    size_t len; 

    printf("Enter the password: ");
    read = getline(&input, &len, stdin);

    unsigned int str_length = (unsigned int)strlen(input);
    if(-1 != read)
        puts(input);
    else
        printf("Received no input\n");

    printf("Size read: %d Len: %zu String Length: %u\n", read, len, str_length);

    MD5hash((unsigned char *)input, str_length, md5_hash);

    printf("MD5 hash is: ");
    for(i = 0; i < MD5_DIGEST_LENGTH; i++){
        printf("%02x", md5_hash[i]);
    } 
    printf("\n");
    free(input);

    return 0;
}

此代码在我的 Mac 上编译并成功运行。当我将12345 作为二进制输入时,我得到的输出是d577273ff885c3f84dadb8578bb41399

 $ ./md5code
 Enter the password: 12345
 12345

 Size read: 6 Len: 8
 String Length: 6
 MD5 hash is: d577273ff885c3f84dadb8578bb41399     

但是,当我运行md5 -s 12345 时,我得到的输出是827ccb0eea8a706c4c34a16891f84e7b,这也是我使用在线工具检查MD5 时得到的输出。

我最初的想法是这是因为 NULL 终止符,所以我用它们计算了字符串的 MD5:

$ md5 -s 12345
MD5 ("12345") = 827ccb0eea8a706c4c34a16891f84e7b
$md5 -s "12345\0"
MD5 ("12345\0") = b04fd4a8d62d25c4b69616ba7f5c5092
$md5 -s 12345\0
MD5 ("123450") = 149787a6b7986f31b3dcc0e4e857cd2a
$md5 -s "12345 "
MD5 ("12345 ") = 43d6757765116456c1c49310cbf8070d
$ md5 -s "12345\n"
MD5 ("12345\n") = 5d44fc965c76c70d2ebe72b4129bc0cd

如您所见,没有一个 MD5 与我从代码中得到的匹配。谁能帮我找出问题所在以及如何解决?谢谢!

注意:我很清楚 MD5 是一个非常弱且损坏的哈希,不应该用于任何实际目的。我这样做只是为了了解基本编码。

【问题讨论】:

  • 我认为您可能遇到换行问题。 getline 应该在返回的字符串中保留换行符。
  • 检查 getline(&input, &len, stdin);按回车键时不存储换行符。它正在作为摘要的一部分进行处理。
  • getline 包含换行符,您显然不希望(也不希望)将其包含在您的 md5 源数据中。在调试器中十秒钟并检查input 字符串将确认这一点。不包括换行符(即使用 str_length-1 作为函数的参数传递 827ccb0eea8a706c4c34a16891f84e7b 应该如此。
  • @MFisherKDX - 好点!我检查了md5 -s "12345\n" 的输出并用它更新了问题。我得到的哈希是5d44fc965c76c70d2ebe72b4129bc0cd,它仍然与我的代码中的哈希不同。
  • @WhozCraig - 谢谢!那很有帮助。如果您将此作为答案发布,我可以接受它作为对我有帮助的答案。您能否还包括您用于调试的方法或包含指向它的链接?我对调试器很熟悉,但对调试过程本身不是很熟悉。

标签: c hash openssl cryptography md5


【解决方案1】:

看看这两个 OpenSSL 命令的输出(你也可以用openssl dgst -md5 命令替换它以获得相同的输出):

$ md5 <(echo 12345)
MD5 (/dev/fd/63) = d577273ff885c3f84dadb8578bb41399
$ md5 <(printf 12345)
MD5 (/dev/fd/63) = 827ccb0eea8a706c4c34a16891f84e7b

后一个是您正在寻找的那个。 echoprintf的区别在于前者加了换行符,后者不加:

$ hexdump -C <(echo 12345)
00000000  31 32 33 34 35 0a                                 |12345.|
00000006
$ hexdump -C <(printf 12345)
00000000  31 32 33 34 35                                    |12345|
00000005

所以是0a给你带来了麻烦。

两个补充说明:&lt;(echo 12345) 构造是Process Substitution 的一个示例,您也可以使用echo -n 代替printf。正如下面的评论所指出的,后者并未标准化。

【讨论】:

  • 你也可以只使用管道,有或没有 printf(但我肯定会使用 printf。)
  • 是的,没错。我更喜欢流程替换看起来很难的方式(至少在今天)。出于好奇,您为什么一定要使用printf
  • 因为 printf 是标准化的。如果您使用echo -n,您将受制于特定外壳中的非标准扩展,您很可能会发现它在您使用的下一个外壳中不起作用。流程替换很难链接,但它肯定是您的选择。我的桌面历史充满了管道链。
  • 好的,谢谢你的解释,很好的动力。我有足够的理由将 echo -n 恢复为 printf,就像我最初拥有的那样。
猜你喜欢
  • 1970-01-01
  • 2016-05-31
  • 2013-04-17
  • 2014-09-30
  • 1970-01-01
  • 1970-01-01
  • 2014-08-26
  • 1970-01-01
  • 2012-07-17
相关资源
最近更新 更多