代码之家  ›  专栏  ›  技术社区  ›  Ken

BadPaddingException:填充块已损坏

  •  7
  • Ken  · 技术社区  · 16 年前

    我正在尝试用Java解密一个文件,这个文件是用Rijndael/CBC/PKCS7用C加密的。我不断得到以下例外:


    在网址:org.bouncycastle.jce.提供程序.JCEBlockCipher.engineDoFinal(未知来源)
    在javax.crypto.Cipher密码.doFinal(DashoA13*)

    doFinal(inpbytes)

    ***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();
       }
    }
    
    4 回复  |  直到 14 年前
        1
  •  6
  •   Neil Coffey    16 年前

    首先,要明确的是,从下面的注释来看,您不应该对每个块都调用doFinal(),因为doFinal()希望在末尾有任何填充,而在中间块中显然没有。要么(a)对中间数据调用update(),然后在末尾调用doFinal(),要么(b)将所有数据放在一个缓冲区或字节数组中,然后对整个作业批调用doFinal()。

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

    如果做不到这一点,那么作为调试的第一步,我建议您选择这两种方法中比较简单的一种:

    • 在ECB模式下解密,没有填充,看看你得到了什么。看看这带来的第一块数据。如果你能将它与你的IV字节异或,得到预期的解密数据,你就知道你的密钥是可以的。
    • 在Base64编码之前从C#中转储实际的密钥字节,在解码并检查它们是否相同之后从Java中转储。

    我记得,C#有无符号字节(而Java有符号),所以在有些地方,字节有符号会出现一些微妙的错误。

        2
  •  3
  •   Bo Persson Touseef    14 年前

    我以前遇到过这个问题。

    当我写了一些代码来进行加密和解密时,就像这样:

        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()]) 当加密数据时,我得到一个异常“pad block corrupted”,所以也许你应该检查你的加密代码。

        4
  •  1
  •   Ken Ken    16 年前

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