错误的 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 加密:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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#中的解密:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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#中加密相同的字符串要短得多。谢谢你的帮助。


1
2
length = 16 - (len(textToEncrypt) % 16)
textToEncrypt += length * b'\\0'

这不是 PKCS7 填充的工作原理。

关于填充的问题是您需要一种方法来识别它,以便以后可以将其删除,而不会意外留下一些或删除一些认为它是填充的数据。

PKCS7 通过使用其值是填充字节数的字节填充来做到这一点。所以填充将是

之一

1
2
3
4
5
6
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 必须是随机不可预测的(它可以是公开的,但不能与您之前加密的内容相同)。随机生成它然后将其添加到密文的开头是很常见的。不要从您的密钥中派生它。