AES/CBC解密未按预期工作



我在Java中使用AES/CCB/PKCS5Padding发布了一些解密数据。我正在加密两个值A和B,然后加密文件中的数据。加密后的值按所述顺序写入文件。当解密各个片段的字节被正确定位(通过调试确认(并且解密函数的输入是正确的时,没有填充问题。

加密代码:

byte[] iv = {..........};
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
Cipher cipher = javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, fileKey, ivParameterSpec);
byte[] encryptedA = cipher.update(A);
byte[] encryptedB = cipher.update(B);
while( true){        

if( blocks > 1 ) {
encrypted = cipher.update(data);
}
else {
encrypted = cipher.doFinal(data);
}
blocks--; 
//write bytes to file
}

加密时,我可以看到密码中的矢量在每次更新后都会更新((,正如预期的那样(最后一个密文是后续更新的矢量。例如encryptedA是我调用update(B(时密码的矢量

解密码

Cipher cipherB = javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding");
cipherB.init(Cipher.DECRYPT_MODE, fileKey, ivParameterSpecB);
byte[] decryptedA = cipherB.update(encryptedA);
byte[] decryptedB = cipherB.update(encryptedB);
while( true){
if(blocks > 1 ) {
decrypted = cipherB.update(encryptedBytes);
}
else {
decrypted = cipherB.doFinal(encryptedBytes);
} 
blocks--; 
//write bytes to file  
}

现在发生的事情非常奇怪。

对cipherB.update(encryptedA(的第一次调用根本不起任何作用。它返回一个空数组,并且不更新密码中的向量。对cipherB.update(encryptedB(的第二次调用返回我从上一次调用中期望的值(cipherB.update(encryptdA(,它是原始值:A(,并将向量设置为encryptedA的值

你能发现我的做法有什么不对吗?使用默认SunJCE提供程序时,AES/CCB/PKCS5Padding中是否存在任何已知问题?

更新:在阅读了一些评论之后,让我添加一些额外的澄清

  1. 条件围绕用于加密有效载荷的块。第一个条件是simplewhile(true(,第二个条件是if(blockCount>1(。在每个循环中都有一个块计数器。代码更新

  2. 如果从加密/解密中省略了A和B,则文件数据已被正确地解密

  3. 我试着解密加密的直接结果例如:

    cipherB.update(cipher.update(A))
    

但我仍然得到相同的空数组,而不是

  1. 在通过运行cipherB.update(encryptedB(返回B后,我不能依赖于运行两次更新。出现问题,文件数据解密受到密码中矢量的影响。我得到的数据有点像

    (12个随机字节(Lorem Ipsum等

明文块和密文块彼此不一一对应。您需要在byte[]中捕获完整的输出,然后自己对其进行解包。

AES/CBC/PKCS5Padding模式在块上工作,因此更新将只返回您的"填充";块,doFinal将返回其余部分。AES使用128位块,因此update方法只返回16字节的倍数。还有一个带有填充的最后一个块。所以你的假设cipherB.update(cipher.update(A))在这种情况下不起作用。

我并不是真的在关注你试图通过条件if(blocks > 1 )实现什么

您可以使用以下代码来处理密码块(简化版(:

byte[] decrypted = null; 
byte[] buffer = new byte[BUFFER_SIZE];
InputStream in = ..;
for (int bytesRead=in.read(buffer); bytesRead>=0; bytesRead=in.read(buffer)) {
decrypted = cipher.update(buffer, 0, bytesRead);
// process the chunk
}
decrypted = cipher.doFinal();
// process the chunk

这样,不管你是否处理一个块。

还有";流密码";或update方法直接返回加密或解密块而不管输入大小的模式,如AES/CTR模式或Salsa20密码

最新更新