BadPaddingException:pad块损坏

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

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

当web服务器为第一个字节[]调用doFinal(inpbytes)方法时。 我猜这是钥匙或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(); 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(); } } 

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

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

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

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

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

我之前遇到过这个问题。

当我写一些代码进行加密和解密时,如下所示:

  Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(sec, "AES"),new IvParameterSpec(new byte[cipher.getBlockSize()])); byte[] encode = cipher.doFinal(data); cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(sec, "AES"), new IvParameterSpec(new byte[cipher.getBlockSize()])); byte[] decode = cipher.doFinal(encode); 

我在加密数据时忘记了第一个IvParameterSpec(new byte[cipher.getBlockSize()]) ,然后我得到了一个exception“pad block corrupted”,所以也许你应该检查加密代码。

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

doFinal()是上面代码的撤消,我最后只使用了密码流而不是update / doFinal方法。 这样我就可以使用FileInputStream和我的密码作为CipherInputStream的参数,然后通过OutputStream将输出传递给Web浏览器。 将更新和doFinal分解为他们自己的方法调用使得任务变得更加困难,并且两个方法都从decrypter类中删除(留下一个while循环读取数据块并将其输出到浏览器)。 在这种情况下也不需要Bouncy Castle Provider而且PKCS5Padding就足够了,这是由SunJCE提供的。