Python和PHP之间的MD5哈希值不一致?

23

我正在尝试创建一个二进制文件 (flv/f4v 等) 的校验和,以验证服务器和客户端计算机之间文件的内容。运行在客户端计算机上的应用程序基于 Python,而服务器则使用 PHP。

以下是 PHP 代码:

$fh = fopen($filepath, 'rb');
$contents = fread($fh, filesize($filepath));
$checksum = md5(base64_encode($contents));
fclose($fh);

以下是Python代码:

def _get_md5(filepath):
    fh = open(filepath, 'rb')
    md5 = hashlib.md5()
    md5.update(f.read().encode('base64'))
    checksum = md5.hexdigest()
    f.close()
    return checksum

在我正在测试的特定文件上,PHP和Python的md5哈希字符串分别如下:

cfad0d835eb88e5342e843402cc42764
0a96e9cc3bb0354d783dfcb729248ce0

服务器运行的是CentOS,而客户端是MacOSX环境。我非常感谢任何帮助我理解为什么这两者会生成不同的哈希结果,或者是否有我忽略的问题(我对Python还比较陌生...)。谢谢!

[事后检查:问题最终在于Python和PHP的base64编码方式不同。MD5在这两个脚本平台上的工作方式相同(至少在Python中使用.hexdigest())。


1
我非常确定文件的base64表示不同,而不是md5算法,你能检查一下吗? - htf
7
为什么要使用base64呢?为什么不直接对原始二进制进行md5处理? - Frank Farmer
2
你为什么要先对文件内容进行base64编码呢?md5函数也能够处理原始二进制数据。正如htf所建议的那样,去掉等式中的base64,看看会发生什么。如果由于某种原因,python和php将base64数据进行了换行(例如进行电子邮件插入),并且选择了不同的换行点,那么这将影响哈希结果,而你却不知道,因为你没有首先检查base64输出是否相等。 - Marc B
非常感谢大家的及时回复!我去掉了base64编码步骤,现在似乎在各方面都完美运行。我甚至不确定为什么我一开始要使用base64编码,可能是为了规范化内容,但最终却让情况变得更糟,哈哈。问题已经解决!谢谢! - thedestry
5
在SO上标记问题“已解决”的方法是接受最能解决问题的答案(点击答案分数下面的复选标志)。 - Dan J
4个回答

25

我会假设 base64 实现不同。

编辑

PHP:

php -r 'var_dump(base64_encode(str_repeat("x", 10)));'
string(16) "eHh4eHh4eHh4eA=="

Python(注意末尾的换行符):

>>> ("x" * 10).encode('base64')
'eHh4eHh4eHh4eA==\n'

6
问题的评论提出了另一个重要观点:如果您想要哈希值,直接对字符串进行哈希即可,无需使用base64。 - soulmerge

14

4
问题似乎在于你对文件数据进行了base-64编码,改变了二进制数据的结构,在php中我认为它不会对文件进行base_64编码。
试试这个方法:
def md5_file(filename):
    //MD5 Object
    crc = hashlib.md5()
    //File Pointer Object
    fp = open(filename, 'rb')

    //Loop the File to update the hash checksum
    for i in fp:
        crc.update(i)

    //Close the resource
    fp.close()

    //Return the hash
    return crc.hexdigest()

在PHP中使用md5_file函数,看看是否可以按预期工作。

Python代码摘自:http://www.php2python.com/wiki/function.md5-file/


4

在使用.encode方法时,Python会向字符串添加一个换行符'\n',因此传入md5函数的输入字符串是不同的。在Python bug追踪器中这个问题有详细的解释。以下是其要点:

>>> import base64
>>> s='I am a string'
>>> s.encode('base64')
'SSBhbSBhIHN0cmluZw==\n'
>>> base64.b64encode(s)
'SSBhbSBhIHN0cmluZw=='
>>> s.encode('base64')== base64.b64encode(s)+'\n'
True

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接