微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

AES / CBC解密无法正常工作

如何解决AES / CBC解密无法正常工作

我正在使用Java中的AES / CBC / 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
}
      

加密时,我可以看到密码中的向量在每次update()之后都按预期进行了更新(最后一个密文是后续更新的向量。例如,cryptoA是我调用update()时密码的向量B)

解密代码

Cipher cipherB = javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding");
cipherB.init(Cipher.DECRYPT_MODE,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(encryptedA),它是原始值:A),将向量设置为cryptonA

的值

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

更新: 阅读了一些评论后,让我添加一些额外的说明

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

  2. 如果在加密/解密过程中省略了A和B,则表示文件数据已正确解密

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

    cipherB.update(cipher.update(A))
    

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

  1. 在通过运行cipherB.update(encryptedB)取回B之后,我不能依靠两次运行更新,这出了问题,并且文件数据解密受密码中的向量影响。 我得到的数据就像

    (12个随机字节)蜂胶等

解决方法

明文和密文块彼此不一对一对应。您需要将整个输出捕获为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,bytesRead);
    // process the chunk
  }
  decrypted = cipher.doFinal();
  // process the chunk

这样,您是否处理单个块都没有关系。

update 方法直接返回加密或解密的块而不考虑输入大小时,也存在“流密码”或模式,例如AES/CTR模式或Salsa20密码

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。