我正在尝试使用AES CBC在Xamarin / .Net / C#prgram和python程序之间共享数据。我能够在.Net中加密消息,并在python中成功解密该消息,反之则不然。也就是说,当我首先在python中加密并尝试在C#中解密该消息时,出现异常:“错误的PKCS7填充。无效的长度0”
这是我在Python中使用的python加密:
salt = 16 * b'\0'
keyIV = PBKDF2(Config.SECRET, salt).read(48)
key = keyIV[:32]
iv = keyIV[-16:]
aes = AES.new(key, AES.MODE_CBC, iv)
# padding
length = 16 - (len(textToEncrypt) % 16)
print(len(textToEncrypt))
textToEncrypt += length * b'\0'
print(len(textToEncrypt))
encrypted = aes.encrypt(textToEncrypt)
encoded = base64.b64encode(encrypted)
return encoded
这是C#中的解密:
if (textToDecrypt == null || textToDecrypt.Length == 0)
return "";
textToDecrypt = textToDecrypt.Replace(" ", "+");
byte[] bytesToDecrypt = Convert.FromBase64String(textToDecrypt);
string decryptedText;
using (Aes aes = Aes.Create())
{
byte[] salt = new byte[16];
Rfc2898DeriveBytes crypto = new Rfc2898DeriveBytes(Config.SECRET, salt);
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.CBC;
aes.Key = crypto.GetBytes(32);
aes.IV = crypto.GetBytes(16);
using (MemoryStream mStream = new MemoryStream())
{
using (CryptoStream cStream = new CryptoStream(mStream, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cStream.Write(bytesToDecrypt, 0, bytesToDecrypt.Length);
}
decryptedText = Encoding.Unicode.GetString(mStream.ToArray());
}
}
return decryptedText;
键和iv在程序之间匹配,但是python中的加密字符串比在C#中加密相同的字符串要短得多。谢谢你的帮助。
length = 16 - (len(textToEncrypt) % 16) textToEncrypt += length * b'\0'
这不是PKCS7填充的工作方式。
关于填充的事情是,您需要一种方法来对其进行标识,以便以后可以将其删除,而不会无意间留下一些东西或删除一些认为它是填充的数据。
PKCS7通过填充其值为填充字节数的字节来完成此操作。因此,填充将是
之一01
02 02
03 03 03
04 04 04 04
...
16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16
为什么填充为16?好吧,如果您的数据长度是块大小的精确倍数(16字节),并且您选择根本不添加任何填充,那么当您删除填充时,您可能会发现数据自然以[C0 ]或01
等,您会删除那些认为它们已填充的有效数据字节。因此,在这种情况下,您需要添加完整的填充块。
您的代码的问题是它使用02 02
值作为填充。
python中的加密字符串比在C#中加密相同的字符串要短得多。谢谢你的帮助。
我认为您可能会混淆编码。 00
是UTF16-LE,每个字符使用2个字节。在Python中使用它是非常不寻常的:您更可能使用的是UTF-8之类的字符,对于常见的西方字符,每个字符使用1个字节。在不知道如何将Python字符串转换为字节字符串的情况下很难确定地说。
[使用AES,IV必须是随机的(可以是公开的,但不能与您加密的先前内容相同)。通常随机生成它,然后将其添加到密文的开头。不要从您的密钥派生它。