BadPaddingException:pad块损坏

7 java encryption exception

我正在尝试使用Rijndael/CBC/PKCS7解密用C#加密的Java文件.我一直得到以下异常:

javax.crypto.BadPaddingException:垫块损坏
在org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(未知来源)
在javax.crypto.Cipher.doFinal(DashoA13*..)
在AESFileDecrypter.decrypt(AESFileDecrypter.java:57)

doFinal(inpbytes)Web服务器为第一个字节[]调用该方法时.我猜这是键或IV的问题.我在我的文件系统上有加密文件进行测试.是否有任何人可以看到我的代码下面明显错误?

***keyStr是base64编码的

public AESFileDecrypter(String keyStr){
    try {
            Security.addProvider(new BouncyCastleProvider());   
            convertIvParameter();
            key = new sun.misc.BASE64Decoder().decodeBuffer(keyStr);

            //use the passed in Base64 decoded key to create a key object
            decryptKey = new SecretKeySpec(key, "AES");

            //specify the encryption algorithm
            decryptCipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");

            //make a parameter object for the initialization vector(IV)             
            IvParameterSpec ivs = new IvParameterSpec(_defaultIv);

            //initialize the decrypter to the correct mode, key used and IV
            decryptCipher.init(Cipher.DECRYPT_MODE, decryptKey, ivs);    
        } 
     catch (Exception e) {
             e.printStackTrace();
     } 
}

public void convertIvParameter() {

   int[] iv = new int[] {11, 190, 165, 33, 68, 88, 11, 200, 245, 35, 68, 23, 60, 24, 223, 67};

   _defaultIv = new byte[16];

   for(int x = 0; x < _defaultIv.length; x++) {
      _defaultIv[x] = (byte)iv[x];
   }
}

public void decryptUpdate(byte[] inpBytes) throws Exception {
   //decrypt the byte passed in from the web server
   decryptCipher.update(inpBytes);  
}

public byte[] decryptFinal() throws Exception {
   //decrypt the byte passed in from the web server
   return decryptCipher.doFinal();
}

//sends bytes to the client for diaply
private void sendBytes(FileInputStream fis, OutputStream os)throws Exception {
    //set the buffer size to send 4k segments of data
aesFileDecrypter = new AESFileDecrypter(<Insert Key string here>);

    byte[] buffer = new byte[4096];
    int bytes = 0, totalBytes = fis.available();

    //while there is still data to be sent keep looping and write the data
    //to the output stream as the buffer is filled
    try {
       while ((bytes = fis.read(buffer)) != -1) {   
          aesFileDecrypter.decryptUpdate(buffer);
          //os.write(buffer, 0, bytes);
       }

       os.write(aesFileDecrypter.decryptFinal(), 0, totalBytes);
   }
   catch(Exception e) {
      e.printStackTrace();
   }
}
Run Code Online (Sandbox Code Playgroud)

Nei*_*fey 6

首先,为了清楚起见,从下面的注释中,你不应该在每个块上调用doFinal(),因为doFinal()期望在结尾处有任何填充,这显然不会在中间块中存在.(a)对中间数据调用update(),然后在末尾调用doFinal(),或者(b)只安排将所有数据放在一个缓冲区或字节数组中,并在整个作业批次上调用doFinal()一次.

从您发布的代码中不清楚这实际上是您在做什么,但应该提到以防万一.

如果不这样做,那么作为调试的第一步,我建议您更容易使用这两个中的哪一个:

  • 在ECB模式下解密,没有填充,看到你得到了什么.看看这带回的第一个数据块.如果您可以使用IV字节对此进行异或并获得预期的解密数据,则表示您的密钥正常.
  • 在基本64位编码之前从C#中转出实际的密钥字节,在解码和检查它们之后将它们转换为Java是相同的.

我记得,C#有无符号字节(而Java签名),所以有一些地方可以解决字节签名的问题.


Dan*_* H. 1

据我所知,AES是基于Rijndael的,但规范并不完全相同。我建议检查您在 C# 中用于加密的密钥和块大小以及在 Java 中使用的大小。(Rijndael 和 AES 之间的 .Net 差异)。