错误的 PKCS7 填充。长度 0 无效。Python 加密到 C# 解密
Bad PKCS7 padding. Invalid length 0. Python Encryption to C# Decryption
我正在尝试在 Xamarin/.Net/C# prgram 和使用 AES CBC 的 python 程序之间共享数据。我能够在 .Net 中加密消息并在 python 中成功解密该消息,但反之亦然。也就是说,当我首先在 python 中加密并尝试在 C# 中解密该消息时,出现异常:"Bad PKCS7 padding. Invalid length 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
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;
length = 16 - (len(textToEncrypt) % 16)
textToEncrypt += length * b'\\0'
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
这是C#中的解密:
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
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;
length = 16 - (len(textToEncrypt) % 16)
textToEncrypt += length * b'\\0'
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
程序之间的密钥和iv匹配,但是python中的加密字符串比C#中加密相同的字符串要短得多。谢谢你的帮助。
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 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; length = 16 - (len(textToEncrypt) % 16) textToEncrypt += length * b'\\0' 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
这不是 PKCS7 填充的工作原理。
关于填充的问题是您需要一种方法来识别它,以便以后可以将其删除,而不会意外留下一些或删除一些认为它是填充的数据。
PKCS7 通过使用其值是填充字节数的字节填充来做到这一点。所以填充将是
之一
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
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;
length = 16 - (len(textToEncrypt) % 16)
textToEncrypt += length * b'\\0'
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 字节)的精确倍数,并且您选择根本不添加任何填充,那么当您删除填充时,您可能会发现您的数据自然以 或 02 02 等,并且您会删除那些认为它们是填充的有效数据字节。所以在这种情况下你需要添加一个完整的填充块。
您的代码的问题在于它使用值 00 作为填充。
the encryption string in python comes out to be much shorter than encrypting the same string in C#. Thanks for any help.
我认为您可能混淆了您的编码。 Encoding.Unicode 是 UTF16-LE,每个字符使用 2 个字节。在 Python 中使用它是非常不寻常的:您更有可能使用 UTF-8 之类的东西,它对常见的西方字符使用每个字符 1 个字节。在不知道如何将 Python 字符串转换为字节字符串的情况下,很难
使用 AES,IV 必须是随机不可预测的(它可以是公开的,但不能与您之前加密的内容相同)。随机生成它然后将其添加到密文的开头是很常见的。不要从您的密钥中派生它。