【发布时间】:2021-04-04 13:36:19
【问题描述】:
C# 代码使用 AES 加密字节数组。
我使用 PyCryptodome 编写了一个 Python 程序来做同样的事情,但是当我使用 C# 代码时,加密的字节总是与结果不同,我确保:
- 将两者的 IV 设置为相同的值(仅用于测试目的)
- 确保两者中的密钥相同
- 确保原始数据相同
我正在加密的内容:一个字节数组。这些字节主要表示 TLD 格式的数据。
Python 程序将成为实用程序的一部分,该实用程序将动态生成流,并由用 C# 编写的 Web 应用程序处理。
使用http://aes.online-domain-tools.com,我实际上可以解密 C# 代码生成的字节,并验证它使用的是 AES,并且原始数据是正确的。
问题是:还有什么可能是鉴别因素?
Python sn-ps:
from Crypto.Cipher import AES
from Crypto import Random
from Crypto.Util.Padding import pad
**** Correction ***
aes_cipher = AES.new(bytes(key, 'UTF-8'), AES.MODE_CBC)
#
# Correct, the above call would use a random IV value.
# For debugging & learning purpose, I halted this in the
# debugger and manually set
# aes_cipher.IV = <a given value>
# and used the same IV in the C# code to try and keep all known inputs identical.
#
aes_cipher.block_size = 128
aes_cipher.key_size = 128 # bits
encrypted_pack = aes_cipher.encrypt(pad(pack, 16))
# Tack on to the beginning the 16 bytes of the "IV"
# FYI - the C# decryption function strips off the first 16 IV bytes
encrypted_pack = aes_cipher.IV + encrypted_pack
return encrypted_pack
C# sn-ps
AesCipher = new RijndaelManaged();
AesCipher.KeySize = 128; // 192, 256
// BlockSize: 128-bit == 16 bytes.
// 128-bit is the default for RijndaelManaged
AesCipher.BlockSize = 128;
AesCipher.Mode = CipherMode.CBC;
AesCipher.Padding = PaddingMode.Zeros;
...
...
#
# Yes, GenerateIV() generates a random IV.
# As mentioned above, I overrode this by setting
# AesCipher.IV = <the same value as above>
#
AesCipher.GenerateIV();
setKey(key); // converts a string of decimal digits to string of hex digits
ICryptoTransform transform = AesCipher.CreateEncryptor();
byte[] encrypted = transform.TransformFinalBlock(buf, 0, buf.Length);
byte[] result = new byte[encrypted.Length + 16];
Buffer.BlockCopy(AesCipher.IV, 0, result, 0, 16);
Buffer.BlockCopy(encrypted, 0, result, 16, encrypted.Length);
return result;
***
Update
***
There was another problem that I just discovered and fixed.
The key was being saved as a 32-byte rather than 16-byte bytearray, which would explain the gigantic discrepancy from online tool results.
Solved easiy with
```byte_key = binascii.unhexlify(key)
Once I did that, the returned by both pieces of code matched, and they matched what was in the online tool, too.
Sneaky because in the debugger, it's easy to miss because the values look the same.
【问题讨论】:
-
AesCipher.GenerateIV()正在生成一个随机 IV,如果我没记错的话。这不同于 在两者中将 IV 设置为相同的值(仅用于测试目的) -
我不太确定
aes_cipher.encrypt(pad(pack, 16))是什么,但听起来好像是在填充数据然后对其进行加密。我不是 Python 程序员,所以我可能是错的,但听起来就是这样。另一方面,您的 C# 代码肯定会加密数据,然后将其复制到结果数组中的偏移位置。 -
与问题中的描述相反,Python 代码中也使用了随机 IV,因为在实例化 AES 对象 s 时没有在第三个参数中传递 IV。 documentation.
-
@John - 我知道如果我不填充输入,那么我会得到一个异常“数据必须在 CBC 模式下填充到 128 字节边界”
-
您的密钥在 sn-ps 中的解码方式也可能不同,但您没有在此处显示该代码。再次检查。此外,如果您明确传递密钥,则不应设置密钥大小。将使用该密钥。如果您设置了密钥大小,那么库很可能会出现异常行为并为您生成新密钥。
标签: python c# encryption aes pycryptodome