端口 hmac.new().digest() 模块从 Python 2.7 到 3.7

Port hmac.new().digest() module from Python 2.7 to 3.7

我已经为此苦苦挣扎了几个小时。我有以下生产代码(为简单起见进行了解析),运行在 Python 2.7 中很好:

import hashlib
import hmac

string1 = 'firststring'
string2 = 'secondstring'

digest = hmac.new(key=string1, msg=string2, digestmod=hashlib.sha256).digest()

print('hmac_digest = ' + digest) # digest is a string

输出是这样的字符串:

hmac_digest = �!�Ni��I.u�����x�l*>a?. �

但是当我 运行 使用 Python3.7 时,出现以下错误:

Traceback (most recent call last):
  File "/home/xxxx/work/py23.py", line 7, in <module>
    digest = hmac.new(key=string1, msg=string2, digestmod=hashlib.sha256).digest()
  File "/usr/lib/python3.7/hmac.py", line 153, in new
    return HMAC(key, msg, digestmod)
  File "/usr/lib/python3.7/hmac.py", line 49, in __init__
    raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__)
TypeError: key: expected bytes or bytearray, but got 'str'

Process finished with exit code 1

经过大量研究后,我了解到 hmac 在 3.4 及更高版本中发生了变化。因此,我将代码重写为以下内容:

import hashlib
import hmac
import base64

string1 = 'firststring'
string2 = 'secondstring'

digest = hmac.new(key=string1.encode('utf-8'), msg=string2.encode('utf-8'), digestmod=hashlib.sha256).digest()
digest = base64.encodebytes(digest).decode('utf-8') # need to convert to string

print('hmac_digest = ' + digest)

但是我得到的输出完全不同!

hmac_digest = 5CEZhgMDTmmFxkkudbGPxaLSytl4+gdsKj4PYT8uAJk=

如何正确地将此代码移植到 python3.7,以便获得与 2.7 完全相同的输出?

提前致谢!

您遇到的问题是,在 Python 2 中,字符串实际上只是字节,而在 Python 3 中,字符串是 unicode 字符串,并且有一个新的 bytes原始字节的数据类型。您可以阅读有关 Python 3 porting guide(和其他地方)中涉及的问题的更多信息。

使您的代码正常工作的最小更改集可能是这样的:

import hashlib
import hmac

string1 = 'firststring'.encode('utf-8')
string2 = 'secondstring'.encode('utf-8')

digest = hmac.new(key=string1, msg=string2, digestmod=hashlib.sha256).digest()

print('hmac_digest = ' + repr(digest)) # digest is a string

这将输出:

hmac_digest = b'\xe4!\x19\x86\x03\x03Ni\x85\xc6I.u\xb1\x8f\xc5\xa2\xd2\xca\xd9x\xfa\x07l*>\x0fa?.\x00\x99'

我们正在打印 hmac 的 repr(),因为它只是一个字节集合。如果你真的想打印出来,你通常会把它转换成十六进制字符串:

digest = hmac.new(key=string1, msg=string2, digestmod=hashlib.sha256).hexdigest()

这将导致:

hmac_digest = 'e421198603034e6985c6492e75b18fc5a2d2cad978fa076c2a3e0f613f2e0099'

感谢 Josh Lee 在 UnicodeDecodeError, invalid continuation byte

中的回答

他关于使用 'latin-1' 解码摘要输出的建议解决了我的问题!

这是我的代码现在在 Python 3.7 中的样子,并为我提供与 Python 2.7 中的代码完全相同的输出:

import hashlib
import hmac

string1 = 'firststring'.encode('utf-8') # can use 'latin-1'
string2 = 'secondstring'.encode('utf-8') # can use 'latin-1' 

digest = hmac.new(key=string1, msg=string2, digestmod=hashlib.sha256).digest()

print('hmac_digest = ' + digest.decode('latin-1')) # Use only 'latin-1' to decode because 'utf-8' or 'ascii' will throw a UnicodeDecodeError