当前位置: 首页 > 知识库问答 >
问题:

AES/CBC解密未按预期工作

段干长恨
2023-03-14

我有一些使用AES / CBC / PKCS5在Java中填充的解密数据。我正在加密两个值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
}
      

加密时,我可以看到Cipher内部的向量在每次更新()后都按预期更新(最后一个密文是后续更新的向量。例如,加密A是我调用更新(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  
}

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

对密码 B.更新(加密 A)的第一次调用根本不执行任何操作。它返回一个空数组,并且不会更新密码中的向量。对密码 B.update(加密 B)的第二次调用返回我从上一次调用(密码 B.update(加密 A))中预期的值,这是原始值:A),并将向量设置为加密的值 A

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

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

> < li>

这些条件与用于加密有效负载的块有关。第一个条件是简单的while(true ),第二个条件是if(blockCount

如果在加密/解密中省略了 A 和 B,则文件数据已正确解密

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

cipherB.update(cipher.update(A))

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

在通过运行cipherB.update(encryptedB)返回B之后,我不能依赖于运行两次更新。有些事情出错了,文件数据解密受到密码中的向量的影响。我得到的数据是这样的

(12 个随机字节)洛雷姆·伊普苏姆等

共有2个答案

贡建修
2023-03-14

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

我不太明白您通过条件< code>if(blocks)想要实现什么

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

  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

这样,无论您是否处理单个块都无关紧要。

当更新方法直接返回加密或解密的块而不考虑输入大小时,也有“流密码”或模式,例如AES/CTR模式或Salsa20cipher

国斌斌
2023-03-14

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

 类似资料:
  • 因为我想在我的程序中同时使用CTR和CBC,所以我想使用一个可以同时处理这两个的AES实现。对于给定的实现,这是可能的吗? 我认为这与定义的填充有关。如果我在解密中使用NoPadding,密码文本被正确解密,但填充没有被移除。如果我在解密时使用PCS5Padding,则返回一个空数组或null。第一次加密也返回一个空数组... IntelliJ在调试时显示的图片 按照zaph的建议添加了doFin

  • 我希望有一个用C编写的程序,可以在没有openssl这样的大型库的帮助下,用AES-CBC对字符串进行编码/解码。 目标: 使用密码短语对字符串进行编码/解码: 因此,应用程序需要接受3个输入参数。。。 输入字符串(待编码)/或已编码字符串(待解码) 用于编码/解码字符串的密码 编码或解码指示器 我对C语言不熟悉(我可以用C#编码)。 我已经找到了https://github.com/kokke/

  • 问题内容: PHP加密功能 当我尝试使用下面的函数在Java中解密此结果时,我得到的只是“ Test @ string”,而我则是“ @@BKxnfÈ〜¯Ô’M”。有什么想法我错了吗?谢谢 问题答案: 编辑:从Java 8开始,Java现在包括可接受的Base64类。 这条线 看起来错了。而是使用apache commons编解码器类或Harder base64 类。同样,mcrypt使用的默认填

  • 我用java编写了这段代码,以便解密密文。我有钥匙。对我来说,一切都是正确的,但我有我要解释的问题。 这是我的代码: 我收到以下错误: 出了什么问题?我知道这个问题在某种程度上与衬垫有关,但我不知道确切的解决方案。我只有一个密文IV和密钥。

  • 我只想用这3种模式测试openSSL中的AES:128192和256密钥长度,但我解密的文本与我的输入不同,我不知道为什么。此外,当我传递一个巨大的输入长度(比如1024字节)时,我的程序显示。。。我的意见总是一样的,但这并不重要,至少现在是这样。代码如下: 编辑: 当我将输出大小更改为而不是时,我得到了结果: 那么,是否有可能存在Outpus大小和IV大小的问题?它们应该有什么尺寸(AES-CB