解密AES / CBC / PKCS5Padding错误:给定最终块没有正确填充

时间:2016-11-03 20:58:37

标签: java security encryption cryptography

在解密大型加密文件上的AES / CBC / PKCS5Padding密码时,我得到给出最后一个块没有正确填充错误。

我认为这个问题是由 cipher.init()方法中添加错误的初始化向量引起的。

我无法在运行时读取整个文件,因此我需要加密固定大小的块。此时我创建了IV并将其存储到.txt文件中。但在解密方法中,我在每个解密周期使用相同的IV。我应该怎么改变这个?

加密

void encrypt() throws Exception{
    char[] password = passwordText.getText().toCharArray();
    byte[] salt = new byte[8];

    /* Creating and saving salt */
    salt = saveSalt(salt);

    /* Securing password */
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
    KeySpec spec = new PBEKeySpec(password, salt, 65536, 128);
    SecretKey tmp = factory.generateSecret(spec);
    SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

    if (choosedFile != null) {
        /* Choosing algorithm for decryption */
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

        /* Getting plain file */
        CipherInputStream fis = new CipherInputStream(new  FileInputStream(choosedFile), cipher);
        CipherOutputStream fos = new CipherOutputStream(new FileOutputStream(choosedFile+".encrypted"), cipher);

        /* Encrypting and Measuring */
        long startTime = System.currentTimeMillis();
        cipher.init(Cipher.ENCRYPT_MODE, secret);
        byte[] rawText = new byte[128];
        int count;
        while((count = fis.read(rawText)) > 0) {
            System.out.println(count);
            byte[] encryptedText = cipher.doFinal(rawText);
            fos.write(encryptedText, 0, count);
        }
        long stopTime = System.currentTimeMillis();

        fis.close();
        fos.close();

        /* Creating initialization vector and storing*/
        byte[] iVector = cipher.getIV();
        saveIVector(iVector);

        text.setText(text.getText() + "File was encrypted in " + (stopTime - startTime) + "ms.\n");
    }

}

解密:

    void decrypt() throws Exception {
    /* Getting salt */
    byte[] salt = getSalt();
    /* Getting initialization vector */
    byte[] iVector = getIVector();
    /* Getting user password */
    char[] password = passwordText.getText().toCharArray();


    /* Securing password */
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
    KeySpec spec = new PBEKeySpec(password, salt, 65536, 128);
    SecretKey tmp = factory.generateSecret(spec);
    SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

    if (choosedFile != null) {

        /* Choosing algorithm for decryption */
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        /* Getting ciphered file */


        CipherInputStream fis = new CipherInputStream(new  FileInputStream(choosedFile), cipher);
        CipherOutputStream fos = new CipherOutputStream(new FileOutputStream(choosedFile+".decrypted"), cipher);

        /* Decrypting and Measuring */
        long startTime = System.currentTimeMillis();
        cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iVector));
        byte[] rawText = new byte[128];
        int count;
        while((count = fis.read(rawText)) > 0) {
                byte[] encryptedText = cipher.doFinal(rawText);
                fos.write(encryptedText, 0, count);
            }

        long stopTime = System.currentTimeMillis();

        fis.close();
        fos.close();

2 个答案:

答案 0 :(得分:1)

担心"直到我不得不将大文件剪切成固定大小的块#34;

使用" chunk"取代"阻止"因为" block"在诸如AES之类的分组密码中具有特定含义。

什么是玩具用块来连接它们?

对于CBC模式,在第一个块之后,先前的加密块值有效地用作下一个块的IV。因此,当拆分然后连接块时,前一个块的最后一个块的值是下一个块的IV。

请参阅CBC mode

或者你在做一些完全不同的事情?

答案 1 :(得分:1)

使用CipherInputStreamCipherOutputStream时,流处理所有对密码的调用(这就是您在初始化时将密码传递给它的原因)。您只需要正确初始化它,然后通过流流式传输数据,密码流就会对update()doFinal()进行必要的调用。请记得关闭蒸汽以触发doFinal()

目前,您的代码以不受控制的方式多次通过密码传递数据,并且数据混乱。

此外,您只需要CipherInputStream进行解密,CipherOutputStream进行加密。在您当前的代码中,您同时使用加密和解密。

加密可能是这样的(这不处理iv ..):

...     
cipher.init(Cipher.ENCRYPT_MODE, secret);
InputStream is = new FileInputStream(choosedFile);
OutputStream os = new CipherOutputStream(new FileOutputStream(choosedFile+".encrypted"), cipher);

byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
    os.write(buffer, 0, len);
}

is.close();
os.close();
...