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字节