Python 2与Python 3. 相同的输入,不同的结果。MD5哈希

8

Python 3 代码:

def md5hex(data):
    """ return hex string of md5 of the given string """
    h = MD5.new()
    h.update(data.encode('utf-8'))
    return b2a_hex(h.digest()).decode('utf-8')

Python 2 代码:

def md5hex(data):
    """ return hex string of md5 of the given string """
    h = MD5.new()
    h.update(data)
    return b2a_hex(h.digest())

请输入Python 3:

>>> md5hex('bf5¤7¤8¤3')
'61d91bafe643c282bd7d7af7083c14d6'

输入Python 2:

>>> md5hex('bf5¤7¤8¤3')
'46440745dd89d0211de4a72c7cea3720'

Whats going on?

EDIT:

def genurlkey(songid, md5origin, mediaver=4, fmt=1):
    """ Calculate the deezer download url given the songid, origin and media+format """
    data = b'\xa4'.join(_.encode("utf-8") for _ in [md5origin, str(fmt), str(songid), str(mediaver)])
    data = b'\xa4'.join([md5hex(data), data])+b'\xa4'
    if len(data)%16:
        data += b'\x00' * (16-len(data)%16)
    return hexaescrypt(data, "jo6aey6haid2Teih").decode('utf-8')

所有这些问题都始于另一个函数中Python 2代码中的b'\xa4'。在Python 3中,此字节无效。

而使用该字节,我可以获得正确的MD5哈希值...


3
你尝试过使用带有前缀u的字符串吗? - Nils Werner
你尝试过使用 from __future__ import unicode_literals 吗? - Gribouillis
使用 \x 记号,我得到了相同的校验和:h=md5("bf5\xc2\xa47\xc2\xa48\xc2\xa43"); h.hexdigest() => 61d91.... - Jean-François Fabre
问题在于Python 2代码中是b'\xa4',但在Python 3中不起作用。 - Eduardo M
@tdelaney,http://pastebin.com/FkNb0GEr 这是原始代码,在Python 2中运行良好,但在3中不行。 - Eduardo M
显示剩余8条评论
2个回答

11

使用hashlib和一个与语言无关的实现代替:

import hashlib
text = u'bf5¤7¤8¤3'
text = text.encode('utf-8')
print(hashlib.md5(text).hexdigest())

在Python 2/3中具有相同的结果:

Python2:

'61d91bafe643c282bd7d7af7083c14d6'

Python3(通过repl.it):

'61d91bafe643c282bd7d7af7083c14d6'

你的代码失败的原因是编码后的字符串与未编码的字符串不相同: 你只为 Python 3 进行了编码。


如果需要匹配未编码的 Python 2:

import hashlib
text = u'bf5¤7¤8¤3'
print(hashlib.md5(text.encode("latin1")).hexdigest())

作品:

46440745dd89d0211de4a72c7cea3720

Python 2 的默认编码是 latin1 而不是 utf-8


我编辑了我的问题,并解释了生成“¤”字符的问题。正确的结果应该是“46440745dd89d0211de4a72c7cea3720”。 - Eduardo M
这是因为原始代码是用Python 2编写的。我声明了编码,因为代码返回了一个KeyError TypeError: Unicode-objects must be encoded before hashing。在Python 2中,正确的方式是不需要进行编码。 - Eduardo M
@EduardoM 因为你想要做的在 Python 3 中是不支持的。 - TemporalWolf
应该有一些变通方法 ... 在 Python 3 中获取正确的哈希值是否不可能? - Eduardo M
@Fakeer 用 Python 2 还是 3?几乎肯定是编码问题,使用 str() 应该可以解决,正如你已经发现的那样。 - TemporalWolf
显示剩余2条评论

1

Python3 的默认编码是 Unicode,而 Python2 的默认编码是 ASCII。因此,即使字符串匹配,读取时它们也会以不同的方式呈现。


有没有解决方案?我需要与 Python 2 代码获得相同的结果。问题出在 '¤' 字符上。 - Eduardo M
你在Python2源代码中声明了编码吗? - Alex Baranowski
我将它放在Python 3源代码中,因为该代码出现了TypeError错误:TypeError:Unicode对象必须在哈希之前进行编码 - Eduardo M
尝试将以下内容放在 #/usr/bin/python 或类似的位置(第一行之后): # -*- coding: utf-8 -*- 然后将文件保存为 utf-8 格式。 最后检查两个文件之间是否有差异 :) - Alex Baranowski
问题只是编码类型的问题。它是Latin1而不是UTF-8。无论如何感谢。 - Eduardo M

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