Python 3中AES加密解密中的字节转字符串

新手上路,请多包涵

我想对字符串进行 AES 加密和解密。但是密钥和消息必须以字节为单位,所以我通过这样做将消息转换为字节:

 b"string"

这是我的 AES 代码:

 # Encryption
encryption_suite = AES.new(b'1234567812345678', AES.MODE_OCB)
cipher_text = encryption_suite.encrypt(b"A really secret message. Not for prying eyes.")

# Decryption
decryption_suite = AES.new(b'1234567812345678', AES.MODE_OCB)
plaintext = decryption_suite.decrypt(cipher_text)

但是我需要将解密的纯文本转回字符串以便阅读。目前明文看起来像这样:

b’x\x85\x92\x9d\xe6\x0bJ\xfe\x9b(\x10G\x8e\x05\xc5\xf4\xcdA9\xc18\xb8_\xf9vbmK\x16\xf8\xa3\xb6’

我尝试使用

plaintext.decode(encoding='windows-1252')

plaintext.decode("utf-8").strip('\x00')

但我得到的只是:

UnicodeDecodeError: ‘charmap’ 编解码器无法解码位置 3 中的字节 0x9d:字符映射到

或这个:

UnicodeDecodeError: ‘utf-8’ 编解码器无法解码位置 1 中的字节 0xb1:无效的起始字节

我需要将这些字节转换回可读字符串。如果您能提供帮助,我们将不胜感激。

原文由 MNS 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 2.3k
2 个回答

您的代码的主要问题是您没有向 AES.new() 提供随机数。 OCB 需要随机数;如果您不提供一个随机数,则每次您创建一个新的 AES 对象时都会创建一个随机数,因此解密将失败。

文档

nonce (字节字符串):一个不可重复的值,长度在 1 到 15 个字节之间。如果不存在,将创建一个推荐长度(15 个字节)的随机随机数。

您有两个选择,要么创建一个随机数并将其传递给 AES.new() (在加密和解密中),要么在加密期间使用 AES 创建的随机数。

接下来,OCB 是一种经过身份验证的加密算法,但您似乎没有检查 MAC。这很重要,因为 MAC 会验证密文的完整性。

AES 的加密和解密方法接受和返回字节。您可以使用 .decode() 将明文(如果是文本)转换为字符串。如果您想将密文转换为字符串,您必须先对其进行 base64 编码,以便将原始字节编码为 ASCII 字符(请记住在解密前解码)。 b64encode() 也返回字节,但可以轻松转换为字符串。

一个例子,

 from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from base64 import b64encode

key = get_random_bytes(16) # A 16 byte key for AES-128
nonce = get_random_bytes(15)
message = "A really secret message. Not for prying eyes.".encode()

cipher = AES.new(key, AES.MODE_OCB, nonce=nonce)
ciphertext, mac = cipher.encrypt_and_digest(message)

cipher = AES.new(key, AES.MODE_OCB, nonce=nonce)
plaintext = cipher.decrypt_and_verify(ciphertext, mac)

print(b64encode(ciphertext).decode())
#CSwHy3ir3MZ7yvZ4CzHbgYOsKgzhMqjq6wEuutU7vJJTJ0c38ExWkAY1QkLO
print(plaintext.decode())
#A really secret message. Not for prying eyes.

请注意,如果 .decrypt_and_verify() 无法验证 MAC a ValueError 将引发异常,因此您可能需要使用 try-except 块。 noncemac 值不是秘密的,将它们存储在密文旁边是安全的。

最后,如果您计划从密码短语派生密钥,您应该使用基于密码的 KDF。 KDF 创建强键,使用 salt 和迭代,并且它们非常能抵抗 fruteforce 攻击。您将在 Crypto.Protocol.KDF 中找到 KDF 函数。

原文由 t.m.adam 发布,翻译遵循 CC BY-SA 4.0 许可协议

您不能将二进制数据转换为字符串,因为它本质上 不是 字符串。是二进制数据。您的加密输出只是偶然地成为格式正确的 UTF8 字符串的可能性很小。

您应该改为查看 base64。它会使数据膨胀(3 个字节到 4 个字符),但更适合您的用例。

编辑:。我的错,我误解了你的问题。您的输出不正确,第一个字节不是 UTF8 中的“1”。这可能是加密/解密的问题。

原文由 Luke Joshua Park 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题