java-javax.crypto.BadPaddingException:给定的最后一个块没有正确填充

java-javax.crypto.BadPaddingException:给定的最后一个块没有正确填充,java,file,encryption,memory-management,aes,Java,File,Encryption,Memory Management,Aes,我正在读一个大文件小字节块。我使用AES 128位加密对该文件进行加密并将每个加密块写入另一个文件。文件已加密成功 但是当我读取那个加密的小字节块文件并试图逐块解密该文件时,它抛出了一个异常 java - javax.crypto.BadPaddingException: Given final block not properly padded 但是当我尝试读取整个文件并尝试解密字节时,它成功地解密 这是我的密码: import javax.crypto.BadPaddingExcepti

我正在
一个
大文件
字节
。我使用
AES 128位加密
对该文件进行
加密
将每个加密块写入另一个文件。文件已
加密
成功

但是当我
读取
那个
加密的
小字节
文件并试图
逐块解密该文件时,它抛出了一个异常

java - javax.crypto.BadPaddingException: Given final block not properly padded 
但是当我尝试读取整个文件并尝试
解密
字节时,它成功地
解密

这是我的密码:

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.File;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

/**
 * Created by Ashish Pancholi on 22-12-2016.
 */
public class EncryDecryPtion implements Securable{
    public static void main(String[] argu){
        EncryDecryPtion encryDecryPtion = new EncryDecryPtion();
        File file = new File("shouldbeoriginal.jpg");
        try {
            encryDecryPtion.encryptFile(file,"Pa$$w0rd");
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        }

        File file_ = new File("shouldbeoriginal.jpg");
        try {
            encryDecryPtion.decryptFile(file_,"Pa$$w0rd");
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        }
    }
} 




import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

/**
 * Encrypt and decrypt file with AES algorithm
 * Created by Ashish Pancholi on 20-12-2016.
 */
public interface Securable {

    /**
     * Read and write the file in chunk.
     * Encrypts the chunks with AES algorithm.
     * It creates a new a file which having encrypted data,
     * deletes old original file and
     * rename a new file with the old file
     * @param file which is to be encrypted and password.
     */

    default File encryptFile(File file, String password) throws IOException, NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchPaddingException {
        AESEncryptionDecryption aesEncryptionDecryption = new AESEncryptionDecryption(password);
        String encryptedFilePath = file.getAbsolutePath() + ".ENCRYPTED";
        File encryptedFile = new File(encryptedFilePath);
        encryptedFile.createNewFile();
        try
                (FileInputStream in = new FileInputStream(file)) {

            try
                    (OutputStream out = new FileOutputStream(encryptedFile)) {
                byte[] chunk = new byte[1024];
                int chunkLen = 0;
                while ((chunkLen = in.read(chunk)) != -1) {
                    byte[] encryptedChunk = aesEncryptionDecryption.encrypt(chunk);
                    out.write(encryptedChunk);
                }
            }
        }
        Path path_originalFile = Paths.get(file.getAbsolutePath());
        Path path_encryptedFile = Paths.get(encryptedFile.getAbsolutePath());
        try {
            Files.delete(path_originalFile);
        }catch (IOException ex){
            try {
                FileUtils.forceDelete(file);
            }catch (IOException ex1){
                //ignore
            }
        }
        Path path = Files.move(path_encryptedFile, path_originalFile);
        return path.toFile();
    }

    default File encryptWholeFile(File file, String password) throws IOException, NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchPaddingException {
        AESEncryptionDecryption aesEncryptionDecryption = new AESEncryptionDecryption(password);
        String encryptedFilePath = file.getAbsolutePath() + ".ENCRYPTED";
        File encryptedFile = new File(encryptedFilePath);
        encryptedFile.createNewFile();
        try(FileInputStream in = new FileInputStream(file)) {
            byte[] bytes = IOUtils.toByteArray(in);
            byte[] encryptedChunk = aesEncryptionDecryption.encrypt(bytes);
            FileUtils.writeByteArrayToFile(encryptedFile, encryptedChunk);
        }
        Path path_originalFile = Paths.get(file.getAbsolutePath());
        Path path_encryptedFile = Paths.get(encryptedFile.getAbsolutePath());
        try {
            Files.delete(path_originalFile);
        }catch (IOException ex){
            try {
                FileUtils.forceDelete(file);
            }catch (IOException ex1){
                //ignore
            }
        }
        Path path = Files.move(path_encryptedFile, path_originalFile);
        return path.toFile();
    }

    /**
     * Read and write the file in chunk.
     * Encrypts the chunks with AES algorithm.
     * It creates a new a file which having encrypted data,
     * deletes old original file and
     * rename a new file with the old file
     * @param inputStream of file which is to be encrypted and a password.
     */
    default InputStream encryptFile(InputStream inputStream, String password) throws IOException, NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchPaddingException {
        InputStream in;
        try {
            AESEncryptionDecryption aesEncryptionDecryption = new AESEncryptionDecryption(password);
            try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                byte[] chunk = new byte[1024];
                int chunkLen = 0;
                while ((chunkLen = inputStream.read(chunk)) != -1) {
                    byte[] encryptedChunk = aesEncryptionDecryption.encrypt(chunk);
                    baos.write(encryptedChunk);
                }
                baos.flush();
                in = new ByteArrayInputStream(baos.toByteArray());
            }
        }finally {
            inputStream.close();
        }
        return in;
    }

    /**
     * Read and write the file in chunk.
     * Encrypts the chunks with AES algorithm.
     * It creates a new a file which having encrypted data,
     * deletes old original file and
     * rename a new file with the old file
     * @param inputStream of file which is to be encrypted and a password.
     */
    default File encryptFile(InputStream inputStream, String password, String targetFileName) throws IOException, NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchPaddingException {
        File encryptedFile = new File(targetFileName);
        try {
            AESEncryptionDecryption aesEncryptionDecryption = new AESEncryptionDecryption(password);
            encryptedFile.getParentFile().mkdirs();
            encryptedFile.createNewFile();
            try (OutputStream baos = new FileOutputStream(encryptedFile)) {
                byte[] chunk = new byte[1024];
                int chunkLen = 0;
                while ((chunkLen = inputStream.read(chunk)) != -1) {
                    byte[] encryptedChunk = aesEncryptionDecryption.encrypt(chunk);
                    baos.write(encryptedChunk);
                }
            }
        }finally {
            inputStream.close();
        }
        return encryptedFile;

    }

    /**
     * Read and write the file in chunk.
     * Decrypts the chunks with AES algorithm.
     * It creates a new a file which having decrypted data,
     * deletes old original encrypted file and
     * rename a new file with the old file
     * @param file which is to be decrypted and password.
     */

    default void decryptFile(File file, String password) throws IOException, NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchPaddingException {
        AESEncryptionDecryption aesEncryptionDecryption = new AESEncryptionDecryption(password);
        String decryptedFilePath = file.getAbsolutePath() + ".DECRYPTED";
        File decryptedFile = new File(decryptedFilePath);
        decryptedFile.createNewFile();
        try
                (FileInputStream in = new FileInputStream(file)) {

            try
                    (OutputStream out = new FileOutputStream(decryptedFile)) {
                byte[] chunk = new byte[1024];
                int chunkLen = 0;
                while ((chunkLen = in.read(chunk)) != -1) {
                    byte[] encryptedChunk = aesEncryptionDecryption.decrypt(chunk);
                    out.write(encryptedChunk);
                }
            }
        }
        Path path_originalFile = Paths.get(file.getAbsolutePath());
        Path path_decryptedFile = Paths.get(decryptedFile.getAbsolutePath());
        try {
            Files.delete(path_originalFile);
        }catch (IOException ex){
            try {
                FileUtils.forceDelete(file);
            }catch (IOException ex1){
                //ignore
            }
        }
        Files.move(path_decryptedFile, path_originalFile);
    }

    default File decryptWholeFile(File file, String password) throws IOException, NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchPaddingException {
        AESEncryptionDecryption aesEncryptionDecryption = new AESEncryptionDecryption(password);
        String decryptedFilePath = file.getAbsolutePath() + ".DECRYPTED";
        File decryptedFile = new File(decryptedFilePath);
        decryptedFile.createNewFile();
        try(FileInputStream in = new FileInputStream(file)) {
                byte[] bytes = IOUtils.toByteArray(in);
                byte[] encryptedChunk = aesEncryptionDecryption.decrypt(bytes);
                FileUtils.writeByteArrayToFile(decryptedFile, encryptedChunk);
          }
        Path path_originalFile = Paths.get(file.getAbsolutePath());
        Path path_decryptedFile = Paths.get(decryptedFile.getAbsolutePath());
        try {
            Files.delete(path_originalFile);
        }catch (IOException ex){
            try {
                FileUtils.forceDelete(file);
            }catch (IOException ex1){
                //ignore
            }
        }
       Path path =  Files.move(path_decryptedFile, path_originalFile);
        return path.toFile();
    }

}


import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;


/**
 * Encrypt and decrypt file with AES algorithm
 * Created by Ashish Pancholi on 20-12-2016.
 */

public class AESEncryptionDecryption {

    private SecretKeySpec secretKey;
    private byte[] key;

    public AESEncryptionDecryption(String password) throws NoSuchAlgorithmException, UnsupportedEncodingException{
        MessageDigest sha = null;
        key = password.getBytes("UTF-8");
        sha = MessageDigest.getInstance("SHA-1");
        key = sha.digest(key);
        key = Arrays.copyOf(key, 16); // use only first 128 bit
        this.secretKey = new SecretKeySpec(key, "AES");
    }

    /**
     * Encrypts the file with AES algorithm
     * @param bytes of file which is to encrypted
     * @return byte[] which is encrypted bytes
     */
    public byte[] encrypt(byte[] bytes) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, this.secretKey);
            byte[] encrytedBytes = cipher.doFinal(bytes);
            return encrytedBytes;

    }

    /**
     * Decrypts the file with AES algorithm
     * @param encrytedBytes of file that to be decrypted
     * @return byte[] which is original data.
     */
    public byte[] decrypt(byte[] encrytedBytes) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException
    {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
        cipher.init(Cipher.DECRYPT_MODE, this.secretKey);
        byte[] bytes = cipher.doFinal(encrytedBytes);
        return bytes;
    }
}
所以我的问题是-如何在不将整个文件加载到内存的情况下加密一个大文件?请帮助

已编辑

这是更新后的代码,但在解密时,我仍然在第
cipher.doFinal()
行遇到相同的异常:

public void encrypt(File sourceFile, File targetFile) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, IOException {
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, this.secretKey);
    try(InputStream inputStream = new FileInputStream(sourceFile)){
        try(OutputStream outputStream = new FileOutputStream(targetFile)){
            byte[] chunk = new byte[8192];
            int chunkLen = 0;
            while ((chunkLen = inputStream.read(chunk)) != -1) {
                byte[] encrytedBytes = cipher.update(chunk);
                outputStream.write(encrytedBytes);
            }
            byte[] finalBytes =  cipher.doFinal();
            if(finalBytes!=null) {
                outputStream.write(finalBytes);
            }
        }
    }
}

public void decrypt(File encryptedFile, File targetFile) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, IOException {
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, this.secretKey);
    try(InputStream inputStream = new FileInputStream(encryptedFile)){
        try(OutputStream outputStream = new FileOutputStream(targetFile)){
            byte[] chunk = new byte[8192];
            int chunkLen = 0;
            while ((chunkLen = inputStream.read(chunk)) != -1) {
                byte[] decrytedBytes = cipher.update(chunk);
                outputStream.write(decrytedBytes);
            }
            byte[] finalBytes =  cipher.doFinal();
            if(finalBytes!=null) {
                outputStream.write(finalBytes);
            }
        }
    }
}

当流式处理文件时,应该使用
cipher.update(…)
方法,并且最后一次调用只能使用
cipher.doFinal(…)
doFinal
刷新缓冲区+执行填充等,您不希望重复执行这些操作

如果过早地在解密过程中执行
doFinal(…)
,则很可能会失败,因为数据中缺少正确的填充

编辑:

不要使用ECB模式,这是不安全的。看一看,然后向下滚动到企鹅


不要通过简单的Sha-1生成密钥-使用适当的密钥派生函数,如。

在文件中进行流式传输时,应使用
cipher.update(…)
方法,并且仅使用
cipher.doFinal(…)
作为最后一次调用。
doFinal
刷新缓冲区+执行填充等,您不希望重复执行这些操作

如果过早地在解密过程中执行
doFinal(…)
,则很可能会失败,因为数据中缺少正确的填充

编辑:

不要使用ECB模式,这是不安全的。看一看,然后向下滚动到企鹅


不要通过简单的Sha-1生成密钥-使用适当的密钥派生函数,如。

最初,我对加密和解密模式都使用
cipher.doFinal()
。运行时执行正常,但测试用例失败,出现
BadPaddingException()
。然后我把代码改成

byte[] output = this.cipher.update(input, 0, input.length);

现在解密工作正常。加密也是如此。

起初,我对加密和解密模式都使用了
cipher.doFinal()
。运行时执行正常,但测试用例失败,出现
BadPaddingException()
。然后我把代码改成

byte[] output = this.cipher.update(input, 0, input.length);

现在解密工作正常。加密也是如此。

我尝试了你的建议。非常感谢你。但是,我仍然无法解密该文件。实际上,在解密文件时,我遵循了您在回答中建议的相同方式,我在流式传输文件时使用了
cipher.update(…)
,但在最后一次调用时使用了
cipher.doFinal(…)
,它再次抛出一个异常-
javax.crypto.BadPaddingException:给定的最后一个块没有正确填充
。这里也发生了一件奇怪的事情-在
解密
中,当我从代码中注释掉
cipher.doFinal(…)
后,文件成功解密(仅通过使用
cipher.update(…)
)。因此,我们在解密时不需要使用
doFinal(…)
?我不知道那是不是真的加密了。黑客解密文件很容易吗?基本上,
cipher.update(…)
在解密时不会失败,即使是随机输入,因为它不会检查解密的数据。如果省略了
doFinal(…)
,最终将丢失最后一块数据,因为这将被卡在缓冲区中,以便进行适当的填充。与明文中的数据相比,您的加密数据有多大?它应该比输入大1到16字节(填充到16的最近倍数)。大小没有变化。顺便提一下我更新了这个问题,在最后添加了两种方法,在这两种方法中,我完全按照您的建议进行操作。请研究一下这些方法,如果我做错了什么,请告诉我。不幸的是,在
解密时调用
doFinal(…)
时,我仍然得到相同的异常。请帮忙。提前感谢。您可以使用
cipher.update(chunk)
加密整个缓冲区,即使chunkLen小于8192。。当数据小于8192时,您需要告诉缓冲区中有多少数据需要加密..我尝试了您的建议。非常感谢你。但是,我仍然无法解密该文件。实际上,在解密文件时,我遵循了您在回答中建议的相同方式,我在流式传输文件时使用了
cipher.update(…)
,但在最后一次调用时使用了
cipher.doFinal(…)
,它再次抛出一个异常-
javax.crypto.BadPaddingException:给定的最后一个块没有正确填充
。这里也发生了一件奇怪的事情-在
解密
中,当我从代码中注释掉
cipher.doFinal(…)
后,文件成功解密(仅通过使用
cipher.update(…)
)。因此,我们在解密时不需要使用
doFinal(…)
?我不知道那是不是真的加密了。黑客解密文件很容易吗?基本上,
cipher.update(…)
在解密时不会失败,即使是随机输入,因为它不会检查解密的数据。如果省略了
doFinal(…)
,最终将丢失最后一块数据,因为这将被卡在缓冲区中,以便进行适当的填充。与明文中的数据相比,您的加密数据有多大?它应该大1到16字节