端口 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
我已经为此苦苦挣扎了几个小时。我有以下生产代码(为简单起见进行了解析),运行在 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