Encryption AES PKCS7填充

Encryption AES PKCS7填充,encryption,cryptography,aes,bouncycastle,pkcs#7,Encryption,Cryptography,Aes,Bouncycastle,Pkcs#7,我刚开始学习用于AES加密/解密的Bouncy Castle。我正在使用带256位密钥的AES/CBC/PKCS7PADDING BC可以成功地对文本进行加密和解密,但是在解密之后,我注意到总会有一些null(0x00)填充,因此我的哈希比较失败。例如,假设原始输入字符串为“1234567890”,则解密的字节数组始终为: {0x49,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x48,0x00,0x00,0x00,0x00,0x00,0x00} 为什么填

我刚开始学习用于AES加密/解密的Bouncy Castle。我正在使用带256位密钥的
AES/CBC/PKCS7PADDING

BC可以成功地对文本进行加密和解密,但是在解密之后,我注意到总会有一些null(0x00)填充,因此我的哈希比较失败。例如,假设原始输入字符串为“1234567890”,则解密的字节数组始终为:

{0x49,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x48,0x00,0x00,0x00,0x00,0x00,0x00}

为什么填充不是
0x06,0x06,0x06,0x06,0x06,0x06,0x06
?是否有任何方法可以确定加密后的填充长度(可以是0),以便在加密前获得完全相同的字符串?

当您指定PKCS7时,BC将在加密前将填充添加到数据中,并在解密时再次将其删除<带有AES的strong>PKCS7始终会添加至少1字节的填充,并将添加足够的数据,使输入成为AES块大小的倍数。解密时,填充被验证为正确,并且在PKCS7的情况下,填充也用作指示最后一块解密数据中有多少是填充,有多少是真实数据

如果在解密步骤中未指定PKCS7而尝试解密加密和填充的数据,则填充仍将在解密的数据中

编辑:

为了说明我的观点。。下面是一些Java代码,它使用AES/CBC/PKCS7对“1234567890”进行加密,然后使用PKCS7填充和不使用PKCS7填充对其再次解密:

公共类BCTest{
public static void doTest()引发异常{
addProvider(新的BouncyCastleProvider());
byte[]clearData=“1234567890”。getBytes();
SecretKey SecretKey=newsecretkeyspec(“0123456789ABCDEF.getBytes(),“AES”);
AlgorithmParameterSpec IVspec=新的IvParameterSpec(“0123456789ABCDEF”.getBytes());
//使用PKCS7填充进行加密
Cipher encrypterWithPad=Cipher.getInstance(“AES/CBC/PKCS7PADDING”,“BC”);
encrypterWithPad.init(Cipher.ENCRYPT_模式,secretKey,IVspec);
字节[]encryptedData=encrypterWithPad.doFinal(clearData);
System.out.println(“加密数据(“+encryptedData.length+”字节):\t“+toHexString(encryptedData));
//用PKCS7键盘解密
Cipher decrypterWithPad=Cipher.getInstance(“AES/CBC/PKCS7PADDING”,“BC”);
decrypterWithPad.init(Cipher.DECRYPT_模式,secretKey,IVspec);
byte[]buffer1=新字节[encryptedData.length];
int decryptedLen1=decrypterWithPad.doFinal(encryptedData,0,encryptedData.length,buffer1);
System.out.println(“用Pad(“+decryptLen1+”字节)解密):\t“+tohextstring(buffer1));
//不使用PKCS7 pad进行解密
Cipher decrypterWithoutPad=Cipher.getInstance(“AES/CBC/NOPADDING”,“BC”);
decrypterWithoutPad.init(Cipher.DECRYPT_模式,secretKey,IVspec);
byte[]buffer2=新字节[encryptedData.length];
int decryptedLen2=decrypterWithoutPad.doFinal(encryptedData,0,encryptedData.length,buffer2);
System.out.println(“在没有Pad的情况下解密(“+decryptLen2+”字节):\t“+toHexString(buffer2));
}
私有静态字符串到HexString(字节[]字节){
返回javax.xml.bind.DatatypeConverter.printHexBinary(字节);
}
公共静态void main(字符串[]args)引发异常{
BCTest.doTest();
}
}
输出:

加密数据(16字节):602CAE14358D0AC5C96E2D46D17E58E3
用Pad解密(10字节):31323334353637383939300000000000
无键盘解密(16字节):31323334353637383933006060606
当使用padding选项进行解密时,输出已从padding中剥离-密码指示解密数据的10字节-缓冲区的其余部分为0填充。如果不使用padding选项进行解密,将导致填充现在成为解密数据的一部分

Edit2:

现在看到原始代码,证实了我的直觉。methode
GetOutputSize
不返回解密字符串的输出大小,只返回输出缓冲区中所需的最大空间。该方法在BC代码中包含以下文档:

/**
*返回更新所需的输出缓冲区大小加上
*doFinal,输入len字节。
*
*@param len输入的长度。
*@返回调用update和doFinal所需的空间
*使用len字节的输入。
*/
DoFinal返回放入缓冲区的解密数据的实际长度

所以在

byte[]plainTextBuffer=新字节[cipher.GetOutputSize(data.Length-IV_Length)];
int length=cipher.DoFinal(数据,iv.length,数据.length-iv.length,明文缓冲区,0);
plainTextBuffer
将略大于实际解密的数据-数据的实际长度将为
length
我使用的是bouncycastle的c。在我看来,这可能是bouncycastle的一个bug,或者至少bouncycastle c#实现没有完全遵循pkcs7规范

我的解决方案是切掉DoFinal返回长度中不包含的尾随字节。仍然不太清楚为什么会有0x00的填充,正如所说的,它根本不应该存在

下面是代码。我使用AES/CBC/PKCS7PADDING进行加密和解密

加密-->

解密--->


您的代码在这里会很有帮助。很可能您的缓冲区是固定大小的,并且您没有将其截断到正确的长度,但是如果没有代码,可能有一些事情是不可能知道的。但是,正如您所说,总是添加一个字节的填充,由于PKCS#7填充中的字节与填充量具有相同的值,因此不能以值为
00
的字节结束。始终添加一个字节的填充,然后在DECRC中删除
        ICipherParameters keyParams = ParameterUtilities.CreateKeyParameter("AES", keyByte);
        ICipherParameters aesIVKeyParam = new ParametersWithIV(keyParams, StringToByteArray(IV_STRING));
        byte[] iv = ((ParametersWithIV) aesIVKeyParam).GetIV();

        IBufferedCipher cipher = CipherUtilities.GetCipher("AES/CBC/PKCS7PADDING");
        cipher.Init(true, aesIVKeyParam);

        byte[] cipherText = new byte[iv.Length + cipher.GetOutputSize(data.Length)];
        Array.Copy(iv, 0, cipherText, 0, iv.Length);
        int length = cipher.DoFinal(data, 0, data.Length, cipherText, iv.Length);
        ICipherParameters keyParams = ParameterUtilities.CreateKeyParameter("AES", keyByte);
        byte[] iv = new byte[IV_LENGTH];
        Array.Copy(data, 0, iv, 0, IV_LENGTH);
        ICipherParameters aesIVKeyParam = new ParametersWithIV(keyParams, iv);

        IBufferedCipher cipher = CipherUtilities.GetCipher("AES/CBC/PKCS7PADDING");
        cipher.Init(false, aesIVKeyParam);

        byte[] plainTextBuffer = new byte[cipher.GetOutputSize(data.Length - IV_LENGTH)];
        int length = cipher.DoFinal(data, iv.Length, data.Length - iv.Length, plainTextBuffer, 0);