【问题标题】:md5 a string multiple times get different result on different platformmd5一个字符串多次在不同平台上得到不同的结果
【发布时间】:2011-06-06 07:48:24
【问题描述】:

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

【问题讨论】:

  • 你能在MD5_Init()MD5_Update()之间打印strlen(in)的结果吗?
  • 不应该将其标记为 C 或 C++ 吗?这就是代码。

标签: python openssl md5


【解决方案1】:

我认为您正在为 MD5 结果分配字节,而不是结束 \0。然后你正在计算内存块的 MD5,它以先前 MD5 计算的结果开始,但后面有一些随机字节。您应该为结果多分配一个字节并将其设置为\0

我的建议:

...
unsigned char * result1 = (unsigned char *)malloc(MD5_DIGEST_LENGTH + 1);
result1[MD5_DIGEST_LENGTH] = 0;
...

【讨论】:

  • 我认为 MD5 结果不是问题;它是一个固定长度的unsigned char 数组。二进制数据,他使用sprintf 将其转换为char const*,它确实附加了'\0'。 (但是对于二进制数据使用std::vector,对于字符串使用std::string,整个事情会更容易和更清晰。)
  • James,长度是固定的,但不是strlen()。我的建议是添加 NULL 终止符,但作者也可以为 md5() 函数添加第二个参数,该函数将对其进行计算的内存块长度。
【解决方案2】:

在我看来,到目前为止的答案并没有足够清楚地说明这个问题。具体问题出在这行:

  MD5_Update(&ctx, in, strlen(in));

您传入的数据块没有'\0' 终止,因此对更新的调用可能会尝试处理超出 MD5_DIGEST_LENGTH 缓冲区末尾的更多字节。简而言之,停止使用strlen() 来计算任意字节缓冲区的长度:你知道缓冲区应该有多长,所以传递长度。

【讨论】:

    【解决方案3】:

    您不会 '\0' 终止您传递给 md5 的字符串(我 假设需要一个'\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&lt;unsigned char&gt;, 并让它返回。而unsigned_to_signed_char 将采取 std::vector&lt;unsigned char&gt; 并返回std::string。)

    【讨论】:

      猜你喜欢
      • 2023-02-10
      • 1970-01-01
      • 1970-01-01
      • 2012-06-12
      • 1970-01-01
      • 1970-01-01
      • 2018-07-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多