【问题标题】:Port hmac.new().digest() module from Python 2.7 to 3.7将 hmac.new().digest() 模块从 Python 2.7 移植到 3.7
【发布时间】:2020-08-17 11:55:39
【问题描述】:

我已经为此苦苦挣扎了好几个小时。我有以下在 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 hash porting hmac


    【解决方案1】:

    您遇到的问题是,在 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'
    

    【讨论】:

    • 感谢您的快速响应,但这仍然没有给我与 Python2.7 中相同的输出。如何获得 Python2 给我的确切字符串?此外, hexdigest() 给出了一个完全不同的字符串,该字符串不适用于将要使用它的模块。 string1 和 string2 是该模块的参数,它们必须提供 python2 提供的确切输出。
    • 数据应该相同,即使通过表示不同。如果您关心字符串的“外观”,您应该只要求十六进制摘要,这两种情况下应该是相同的。原始摘要并不是真正要打印的。 “ �” 意义不大。
    • 是的,它对打印不是非常有用,但原始摘要输入另一个模块,在那里它被解析(作为字符串)并转换以供进一步使用。由于安全原因,我无法向您提供接收器模块,但我会找到另一种方法来澄清它。感谢快速的答案!
    【解决方案2】:

    感谢 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-28
      • 2018-12-20
      • 2015-06-09
      相关资源
      最近更新 更多