我正在尝试在Python 3中使用pyaes(https://github.com/ricmoo/pyaes/blob/master/README.md)来使用pya来加密和解密文本。当我加密文本时,我给pya一个str
值,即
plaintext = 'plain text'
key = os.urandom(16)
aes = pyaes.AESModeOfOperationCTR(key)
ciphertext = aes.encrypt(plaintext)
当我解密时,我得到了bytes
类型:
aes = pyaes.AESModeOfOperationCTR(key)
decrypted_plaintext = aes.decrypt(ciphertext)
打印decrypted_plaintext
会产生以下输出,该输出似乎包含原始文本:
b'plain text'
但它并不完全相同;一个是str
,另一个是bytes
:
plaintext == decrypted_plaintext # False
我正在努力理解bytes
与Python 3的str
内部表示之间的关系。如何将bytes
类型转换为str
以获取我的纯文本?
我已经确认在pyaes自述文件页面上运行示例会遇到同样的问题。我猜这将与编码有关。
答案 0 :(得分:1)
在Python 3 str
中,type表示unicode格式的字符串。它由相对抽象的代码点组成,即数字编码字符。
有几种方法可以将这些代码点转换(编码)为实际字节,这些字节称为“编码”。 utf-8和utf-16是一些允许编码unicode字符的编码。
请注意,某些编码(如ASCII)不允许对unicode字符进行编码。
在Python中编码str
字符串时,您将获得类型为bytes
的字节列表。然后,您可以解码此字节列表以获取str
字符串。
要记住的一点是,您必须指定一个编码来编码str
字符串,并且您必须知道bytes
字符串的编码才能对其进行解码。如果您没有指定编码,Python将尝试使用其默认编码进行编码和解码,您可以获得“随机”结果。
在特定情况下,差异是不可见的,因为字符串的所有字符都是ASCII字符,幸运的是,unicode的128个第一个代码点与ASCII表匹配。
尝试在字符串中引入一些'exeotic'字符(如é,ç或Ë),你会看到差异。
现在,pyaes不会加密/解密unicode代码点,而是加密/解密字节。 因此,您必须对加密的字符串进行编码,并且必须知道使用的编码来解码解密的字符串。
Python doc中的更多信息:
答案 1 :(得分:0)
decrypted_plaintext.decode()
会给你一个str
,这很可能就是你想要的。 bytes
对象是未指定编码的原始字节字符串。要将其转换为str
,您必须告诉Python使用decode()
对其进行解码。 decode()
默认为UTF-8,但您可以告诉它使用哪种编码。
我只是看了source,我看不到特定于编码的内容,因此解密后的字符串的编码应该与加密字符串的编码匹配。
答案 2 :(得分:0)
对于所有其他人,这可以帮助您:如果 decrypted.decode('utf-8') ==明文:
# A 256 bit (32 byte) key
key = b"This_key_for_demo_purposes_only!"
aes = pyaes.AESModeOfOperationCTR(key)
plaintext = "Text may be any length you wish, no padding is required"
ciphertext = aes.encrypt(plaintext)
# '''\xb6\x99\x10=\xa4\x96\x88\xd1\x89\x1co\xe6\x1d\xef;\x11\x03\xe3\xee
# \xa9V?wY\xbfe\xcdO\xe3\xdf\x9dV\x19\xe5\x8dk\x9fh\xb87>\xdb\xa3\xd6
# \x86\xf4\xbd\xb0\x97\xf1\t\x02\xe9 \xed'''
print (repr(ciphertext))
# The counter mode of operation maintains state, so decryption requires
# a new instance be created
aes = pyaes.AESModeOfOperationCTR(key)
decrypted = aes.decrypt(ciphertext)
print(type(decrypted))
print(type(plaintext))
# True
if decrypted.decode('utf-8') == plaintext:
print(plaintext)
print(True)
print(decrypted.decode('utf-8'))
# '''WZ\x844\x02\xbfoY\x1f\x12\xa6\xce\x03\x82Ei)\xf6\x97mX\x86\xe3\x9d
# _1\xdd\xbd\x87\xb5\xccEM_4\x01$\xa6\x81\x0b\xd5\x04\xd7Al\x07\xe5
# \xb2\x0e\\\x0f\x00\x13,\x07'''
print (repr(ciphertext))