当纯文本字符数 > 16 时,C# 到 Python 密文不同

C# to Python Cipher Text Differs When Plain Text Character Count > 16

我想将 c# 代码转换为 python 就像这个问题:Python to C# AES CBC PKCS7

当纯文本的字符数 < 16 时,我给出的这两个代码的结果相同。 (24 个字符)

但是当纯文本的字符数 >= 16 时,C# 代码 returns 结果有 44 个字符,python returns 结果有 24 个字符。这是相同的字符,但缺少 python。 例如:c#结果为jfgdohpE8zrgls3Mpi8B+t/nGbzK1iEA3l1rJ0G8sFU=, python 结果是 jfgdohpE8zrgls3Mpi8B+g== 为什么? (我使用 Python3 和 PKCS7 库进行填充)

首先,行

AES_KEY = bytearray(bbb, 'utf-8') 

必须在 Python 代码中删除才能导出与 C# 代码中相同的密钥。

那么你描述的问题就可以重现了:C#代码returns例如对于 base64 编码的 IV J223ULe3Xf6PX1KfNVmEiw== 和您发布的明文和密钥,以下密文:

O5EBcIB987RNfZ41RbvRThmlEyP2RxkDCuGWQiajkDY=

而 Python 代码生成此密文:

O5EBcIB987RNfZ41RbvRTg==

原因是 pypkcs7 (issue #1) 中的一个已知错误,这使得这个包实际上无法使用,因为填充通常不再符合 PKCS7 定义(特别是如果填充前的明文长度是块大小的整数倍(AES 为 16 字节))。

因此您需要不同的 PKCS7 实现。幸运的是 PyCryptodome 提供了一个 padding module(旧版 PyCrypto 中不可用)。进行以下更改

#from pkcs7 import PKCS7Encoder
from Crypto.Util.Padding import pad
...
#encoder = PKCS7Encoder()
#padded_text = encoder.encode(secret_text)    
padded_text = pad(secret_text.encode('utf8'), 16).decode('utf8')  

生成了和C#代码一样的密文(顺便说一句,解码其实可以省略,因为加密过程又对密文进行了编码;我保留这个只是为了与旧实现进行比较).

附带说明一下,可以更轻松地导出密钥:

hash = hashlib.sha256(bbb.encode('utf8')).digest() 
AES_KEY = hash[:15] + hash[:16] + b"[=14=]"