在不同平台上多次对同一字符串进行md5运算结果不同
t.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/md5.h>
static char* unsigned_to_signed_char(const unsigned char* in , int len) {
char* res = (char*)malloc(len * 2 + 1);
int i = 0;
memset(res , 0 , len * 2 + 1);
while(i < len) {
sprintf(res + i * 2 , "%02x" , in[i]);
i ++;
};
return res;
}
static unsigned char * md5(const unsigned char * in) {
MD5_CTX ctx;
unsigned char * result1 = (unsigned char *)malloc(MD5_DIGEST_LENGTH);
MD5_Init(&ctx);
printf("len: %lu \n", strlen(in));
MD5_Update(&ctx, in, strlen(in));
MD5_Final(result1, &ctx);
return result1;
}
int main(int argc, char *argv[])
{
const char * i = "abcdef";
unsigned char * data = (unsigned char *)malloc(strlen(i) + 1);
strncpy(data, i, strlen(i));
unsigned char * result1 = md5(data);
free(data);
printf("%s\n", unsigned_to_signed_char(result1, MD5_DIGEST_LENGTH));
unsigned char * result2 = md5(result1);
free(result1);
printf("%s\n", unsigned_to_signed_char(result2, MD5_DIGEST_LENGTH));
unsigned char * result3 = md5(result2);
free(result2);
printf("%s\n", unsigned_to_signed_char(result3, MD5_DIGEST_LENGTH));
return 0;
}
makeflle
all:
cc t.c -Wall -L/usr/local/lib -lcrypto
还有 t.py
#!/usr/bin/env python
import hashlib
import binascii
src = 'abcdef'
a = hashlib.md5(src).digest()
b = hashlib.md5(a).digest()
c = hashlib.md5(b).hexdigest().upper()
print binascii.b2a_hex(a)
print binascii.b2a_hex(b)
print c
在 Debian6 x86 和 MacOS 10.6 上运行的 Python 脚本结果是一样的:
e80b5017098950fc58aad83c8c14978e
b91282813df47352f7fe2c0c1fe9e5bd
85E4FBD1BD400329009162A8023E1E4B
在 MacOS 上的 C 版本是:
len: 6
e80b5017098950fc58aad83c8c14978e
len: 48
eac9eaa9a4e5673c5d3773d7a3108c18
len: 64
73f83fa79e53e9415446c66802a0383f
为什么它和 Debian6 的结果不一样?
Debian 环境:
gcc (Debian 4.4.5-8) 4.4.5
Python 2.6.6
Linux shuge-lab 2.6.26-2-686 #1 SMP Thu Nov 25 01:53:57 UTC 2010 i686 GNU/Linux
OpenSSL 是从测试库安装的。
MacOS 环境:
i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5666) (dot 3)
Python 2.7.1
Darwin Lees-Box.local 10.7.0 Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386 i386
OpenSSL 是从 MacPort 安装的。
openssl @1.0.0d (devel, security)
OpenSSL SSL/TLS cryptography library
3 个回答
你传给 md5
的字符串没有以 '\0'
结尾(我猜这个函数需要一个以 '\0'
结尾的字符串,因为你没有给它传长度)。这段代码
memset( data, 0, sizeof( strlen( i ) ) );
memcpy( data, i, strlen( i ) );
是完全错误的:sizeof( strlen( i ) )
的结果和 sizeof( size_t )
是一样的,通常是4或8个字节。但其实你根本不需要 memset
。试着把这些替换成:
strcpy( data, i );
或者更好的是:
std::string i( "abcdef" );
然后把 i.c_str()
传给 md5
(并且声明 md5
接受一个 char const*
类型的参数)。我建议在 md5()
中使用 std::vector<unsigned char>
,并让它返回这个向量。而 unsigned_to_signed_char
则可以接收这个 std::vector<unsigned char>
并返回一个 std::string
类型的结果。)
到目前为止,大家的回答似乎没有把问题说得很清楚。具体来说,问题出在这一行:
MD5_Update(&ctx, in, strlen(in));
你传入的数据块没有以'\0'
结束,这样在调用更新时,可能会尝试处理超出MD5_DIGEST_LENGTH缓冲区末尾的更多字节。简单来说,不要再用strlen()
来计算任意字节缓冲区的长度:你应该知道这些缓冲区应该有多长,所以直接把长度传递过去就行了。
我觉得你分配的字节数正好是MD5结果的大小,但没有多留一个字节来放结束符\0
。这样的话,你在计算MD5的时候,是从之前计算的结果开始,然后后面跟着一些随机的字节。你应该多分配一个字节给结果,并把这个字节设置为\0
。
我的建议是:
...
unsigned char * result1 = (unsigned char *)malloc(MD5_DIGEST_LENGTH + 1);
result1[MD5_DIGEST_LENGTH] = 0;
...