3

我用 C 中的 openssl 编写了一个简单的示例。我想从我的消息中计算 MD4 哈希,但我想将结果保存到一个 char 数组中。这是我的带有注释的代码,可以帮助您理解我想要实现的目标:

#include <string.h>
#include <openssl/md4.h>
#include <stdio.h>

int main()
{
    unsigned char digest[MD4_DIGEST_LENGTH];
    char string[] = "hello world";

    // run md4 for my msg
    MD4((unsigned char*)&string, strlen(string), (unsigned char*)&digest);

    // save md4 result into char array - doesnt work
    char test[MD4_DIGEST_LENGTH];
    sprintf(test, "%02x", (unsigned int)digest);
    for(int i = 0; i < MD4_DIGEST_LENGTH; i++)
        printf("%02x", test[i]);
    printf("\n\n");

    // print out md4 result - works, but its not intochar array as I wanted it to be
    for(int i = 0; i < MD4_DIGEST_LENGTH; i++)
        printf("%02x", digest[i]);
    printf("\n\n");

    // works but i dont understand why 'mdString' is 33 size
    char mdString[33];
    for(int i = 0; i < MD4_DIGEST_LENGTH; i++)
    // and I also dont get i*2 in this loop
         sprintf(&mdString[i*2], "%02x", (unsigned int)digest[i]);
    printf("md4 digest: %s\n", mdString);

    return 0;
}

问题是,为什么下面的代码不起作用,它显示的 md4 值与应有的不同:

char test[MD4_DIGEST_LENGTH];
        sprintf(test, "%02x", (unsigned int)digest);
        for(int i = 0; i < MD4_DIGEST_LENGTH; i++)
            printf("%02x", test[i]);
        printf("\n\n");

我怎么知道应该是什么尺寸mdString以及为什么i*2在最后一个循环中有?有人可以解释一下吗?

4

1 回答 1

5

首先,您的调用为and数组MD4()提供了不正确的地址:通过使用,您得到的是数组的地址 ( ),而不是第一个字符的地址。由于您是显式转换and to ,因此编译器不会警告您。移除铸件,您将收到以下警告:stringdigest&char **&string&digestunsigned char*

warning: passing argument 1 of 'MD4' from incompatible pointer type

所以改为这样调用MD4()

MD4(string, strlen(string), digest);

我个人更喜欢避免显式转换指针,除非确实有必要,这样你会更容易发现不正确的类型转换。

接下来,您尝试使用sprintf()转换digest为十六进制整数:sprintf(test, "%02x", (unsigned int)digest);. 这里有两点错误:(a)因为digest本质上是一个字符指针,即:内存地址,所以您将此地址转换为无符号整数,然后将该整数转换为十六进制;(b) 你需要遍历元素digest并将每个元素转换为一个字符,snprintf不会为你这样做!

鉴于所犯的错误,我看到你可能对 C 语言比较陌生,但不要灰心,犯错是学习的方式!:)

如果你买得起这本书,我强烈推荐 Stephen Prata 的“C Primer Plus”。对于刚开始编程的任何人来说,这都是一个很好的介绍,并且当您已经熟悉该语言时,它是一个非常完整的参考,供您以后使用。否则,网上有很多资料,谷歌搜索“C 指针教程”会返回几个有用的结果。

希望这可以帮助!


编辑:

忘记评论其他确实有效的代码片段,但使用 33 个字节来存储字符串化的 MD4 哈希:

// works but i dont understand why 'mdString' is 33 size
char mdString[33];
for(int i = 0; i < MD4_DIGEST_LENGTH; i++)
// and I also dont get i*2 in this loop
     sprintf(&mdString[i*2], "%02x", (unsigned int)digest[i]);
printf("md4 digest: %s\n", mdString);

openssl 手册页声明哈希为MD4() 16字节长。知道了这一点,并且每个 unsigned char 可以保存一个从 0 到 255 的值这一事实,那么任何单个元素的最大十六进制表示为digest0xFF,换句话说,每个 unsigned char 有 2 个 ASCII 字符。

(33)的大小msString显得神秘的原因是因为MD4_DIGEST_LENGTH应该用于计算数组的大小:您需要 2 个字符来表示digest+ 1 个空终止符 ('\0') 中的每个元素来结束字符串:

char mdString[(MD4_DIGEST_LENGTH * 2) + 1];

sprintfmdString只要从 输入 1 个字节,就会向数组打印 2 个字符,因此您需要为 中的每个位置digest提前 2 个索引位置,因此使用. 以下产生与使用相同的结果:mdStringdigesti * 2i * 2

for(int i = 0, j = 0; i < MD4_DIGEST_LENGTH; i++, j += 2)
     sprintf(&mdString[j], "%02x", (unsigned int)digest[i]);
于 2013-07-13T18:34:43.880 回答