我用 C 语言用 openssl 写了一个简单的例子。我想从我的消息中计算 MD4 哈希值,但我想将结果保存到一个字符数组中。这是我的带有注释的代码,可以帮助您了解我想要实现的目标:
#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;
}
Run Code Online (Sandbox Code Playgroud)
问题是,为什么下面的代码不起作用,它显示的 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");
Run Code Online (Sandbox Code Playgroud)
以及我如何知道应该是什么尺寸mdString以及为什么i*2在最后一个循环中存在?有人可以解释一下吗?
首先,您MD4()对string和digest数组的调用提供了错误的地址:通过使用&,您将获得数组的地址 ( char **),而不是第一个字符的地址。由于您显式地强制转换&string和&digestto unsigned 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 比较陌生,但不要气馁,犯错误是学习的方式!:)
如果你买得起这本书,我强烈推荐斯蒂芬普拉塔的“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);
Run Code Online (Sandbox Code Playgroud)
openssl 联机帮助页MD4() 指出散列长度为 16 字节。知道这一点,以及每个无符号字符可以保存一个从 0 到 255 的值的事实,那么任何单个元素的最大十六进制表示digest是 0xFF,换句话说,每个无符号字符有 2 个 ASCII 字符。
msString(33)的大小之所以显得神秘,是因为MD4_DIGEST_LENGTH应该用于计算数组的大小:您需要 2 个字符来表示digest+ 1 空终止符 ('\0') 中的每个元素来结束字符串:
char mdString[(MD4_DIGEST_LENGTH * 2) + 1];
Run Code Online (Sandbox Code Playgroud)
sprintfmdString每当从 输入 1 个字节时,将向数组打印 2 个字符digest,因此您需要为 中mdString的每个位置提前 2 个索引位置digest,因此使用i * 2. 以下产生与使用相同的结果i * 2:
for(int i = 0, j = 0; i < MD4_DIGEST_LENGTH; i++, j += 2)
sprintf(&mdString[j], "%02x", (unsigned int)digest[i]);
Run Code Online (Sandbox Code Playgroud)