错误 decrjavax.crypto.BadPaddingException:给定的最终块未正确填充。如果在解密过程中使用了错误的密钥,就会出现此类问题
error decrjavax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption
我在使用 Java 密码学时遇到以下问题。
error decrjavax.crypto.BadPaddingException: Given final block not
properly padded. Such issues can arise if a bad key is used during
decryption.
我已经检查了所有可能的答案,但找不到这背后的确切原因。
一个观察,当我使用 AES/CBC/NoPadding 代替 AES/CBC/PKCS5Padding 时,我可以成功执行它。
这是我的代码片段。
package demo;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
public class TestEncryption {
private static final int BUFFER_SIZE = 32;
private static final int KEY_ITERATIONS = 65535;
private static final int DEFAULT_KEY_BITS = 128;
private static final String ALGORITHM = "AES/CBC/PKCS5Padding";
private static final String TRANSFORMATION = "AES";
private static final String PBKDF_2_WITH_HMAC_SHA_256 = "PBKDF2WithHmacSHA256";
private static final int IV_SIZE = 16;
private final Cipher ecipher;
private final Cipher dcipher;
private SecretKey secretKey;
/**
* Initialize the ciphers using the given key.
* @param key
* @param keyBits
*/
public TestEncryption(String key, int keyBits) {
byte[] salt = new byte[8];
if (key.length() < 8) {
throw new IllegalArgumentException("key must contain 8 characters or more");
}
for (int i = 0; i < 8; i = i + 1) {
salt[i] = ((byte) key.charAt(i));
}
char[] password = key.toCharArray();
int keyLength = DEFAULT_KEY_BITS;
try {
SecretKeyFactory factory = SecretKeyFactory.getInstance(PBKDF_2_WITH_HMAC_SHA_256);
if (keyBits == 256) {
keyLength = 256;
}
KeySpec spec = new PBEKeySpec(password, salt, KEY_ITERATIONS, keyLength);
secretKey = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), TRANSFORMATION);
ecipher = Cipher.getInstance(ALGORITHM);
dcipher = Cipher.getInstance(ALGORITHM);
} catch (InvalidKeySpecException | NoSuchPaddingException | NoSuchAlgorithmException e) {
throw new RuntimeException("Failed to initialize encryption.", e);
}
}
public void encryptFile(File src, File dest){
try {
InputStream inputStream = new FileInputStream(src);
OutputStream outputStream = new FileOutputStream(dest);
CipherOutputStream cipherOutputStream= new CipherOutputStream(outputStream, ecipher);
// Generating IV.
byte[] iv = new byte[IV_SIZE];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// First write the IV at the beginning of the encrypted file.
outputStream.write(iv, 0, IV_SIZE);
System.out.println("key " + secretKey);
// Initialize cipher with IV
ecipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
// Encrypt input file and write in to output
while ((bytesRead = inputStream.read(buffer)) > 0) {
cipherOutputStream.write(buffer, 0, bytesRead);
}
} catch (InvalidKeyException | InvalidAlgorithmParameterException | IOException e) {
System.out.println("error encryption" + e.getMessage());
e.printStackTrace();
}
}
public void decryptFile(File srcFile, File destFile) {
try (
InputStream is = new FileInputStream(srcFile);
OutputStream out = new FileOutputStream(destFile);
CipherInputStream cis = new CipherInputStream(is, dcipher)
) {
// Extract IV
byte[] iv = new byte[IV_SIZE];
is.read(iv, 0, IV_SIZE);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// Initialize cypher with IV
dcipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = cis.read(buffer)) > 0) {
out.write(buffer, 0, bytesRead);
}
} catch ( InvalidKeyException | InvalidAlgorithmParameterException | IOException e) {
System.out.println("error decr" + e.getMessage());
e.printStackTrace();
}
}
}
package demo;
import java.io.*;
public class Client {
public static void main(String [] args){
File tempFile =null, src = null, dest = null;
try {
tempFile = new File("temp.txt");
src = new File("C:\Users\x\Desktop\test.txt");
dest = new File("C:\Users\x\Desktop\out.txt");
TestEncryption encryption = new TestEncryption("helloworld", 256);
encryption.encryptFile(src, tempFile);
encryption.decryptFile(tempFile, dest);
}
finally {
tempFile.delete();
//src.delete();
//dest.delete();
}
}
}
您的错误是加密时使用流的方式:
对于CipherOutputStream
,必须在最后关闭,因为只有在关闭时才能写入最后的填充。
但是在您的代码中,cipherOutputStream
实例永远不会关闭。因此填充永远不会写入加密文件。
当然,在解密文件时,应该填充的地方没有填充,您得到的是 BadPaddingException
。
因此您应该将加密更改为:
public void encryptFile(File src, File dest) {
try (InputStream inputStream = new FileInputStream(src);
OutputStream outputStream = new FileOutputStream(dest)) {
try (CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, ecipher)) {
// Generating IV.
byte[] iv = new byte[IV_SIZE];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// First write the IV at the beginning of the encrypted file.
outputStream.write(iv, 0, IV_SIZE);
System.out.println("key 0x" + new BigInteger(1, secretKey.getEncoded()).toString(16));
// Initialize cipher with IV
ecipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
// Encrypt input file and write in to output
while ((bytesRead = inputStream.read(buffer)) >= 0) {
cipherOutputStream.write(buffer, 0, bytesRead);
}
}
} catch (InvalidKeyException | InvalidAlgorithmParameterException | IOException e) {
System.out.println("error encryption" + e.getMessage());
e.printStackTrace();
}
}
public void decryptFile(File srcFile, File destFile) {
try (InputStream is = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile)) {
try (CipherInputStream cis = new CipherInputStream(is, dcipher)) {
// Extract IV
byte[] iv = is.readNBytes(IV_SIZE);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// Initialize cypher with IV
dcipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = cis.read(buffer)) >= 0) {
out.write(buffer, 0, bytesRead);
}
}
} catch (InvalidKeyException | InvalidAlgorithmParameterException | IOException e) {
System.out.println("error decr" + e.getMessage());
e.printStackTrace();
}
}
还有一个原因可能是你需要描述的内容,但是传递给方法时参数为null,也会抛出badpaddedException。
我在使用 Java 密码学时遇到以下问题。
error decrjavax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
我已经检查了所有可能的答案,但找不到这背后的确切原因。
一个观察,当我使用 AES/CBC/NoPadding 代替 AES/CBC/PKCS5Padding 时,我可以成功执行它。
这是我的代码片段。
package demo;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
public class TestEncryption {
private static final int BUFFER_SIZE = 32;
private static final int KEY_ITERATIONS = 65535;
private static final int DEFAULT_KEY_BITS = 128;
private static final String ALGORITHM = "AES/CBC/PKCS5Padding";
private static final String TRANSFORMATION = "AES";
private static final String PBKDF_2_WITH_HMAC_SHA_256 = "PBKDF2WithHmacSHA256";
private static final int IV_SIZE = 16;
private final Cipher ecipher;
private final Cipher dcipher;
private SecretKey secretKey;
/**
* Initialize the ciphers using the given key.
* @param key
* @param keyBits
*/
public TestEncryption(String key, int keyBits) {
byte[] salt = new byte[8];
if (key.length() < 8) {
throw new IllegalArgumentException("key must contain 8 characters or more");
}
for (int i = 0; i < 8; i = i + 1) {
salt[i] = ((byte) key.charAt(i));
}
char[] password = key.toCharArray();
int keyLength = DEFAULT_KEY_BITS;
try {
SecretKeyFactory factory = SecretKeyFactory.getInstance(PBKDF_2_WITH_HMAC_SHA_256);
if (keyBits == 256) {
keyLength = 256;
}
KeySpec spec = new PBEKeySpec(password, salt, KEY_ITERATIONS, keyLength);
secretKey = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), TRANSFORMATION);
ecipher = Cipher.getInstance(ALGORITHM);
dcipher = Cipher.getInstance(ALGORITHM);
} catch (InvalidKeySpecException | NoSuchPaddingException | NoSuchAlgorithmException e) {
throw new RuntimeException("Failed to initialize encryption.", e);
}
}
public void encryptFile(File src, File dest){
try {
InputStream inputStream = new FileInputStream(src);
OutputStream outputStream = new FileOutputStream(dest);
CipherOutputStream cipherOutputStream= new CipherOutputStream(outputStream, ecipher);
// Generating IV.
byte[] iv = new byte[IV_SIZE];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// First write the IV at the beginning of the encrypted file.
outputStream.write(iv, 0, IV_SIZE);
System.out.println("key " + secretKey);
// Initialize cipher with IV
ecipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
// Encrypt input file and write in to output
while ((bytesRead = inputStream.read(buffer)) > 0) {
cipherOutputStream.write(buffer, 0, bytesRead);
}
} catch (InvalidKeyException | InvalidAlgorithmParameterException | IOException e) {
System.out.println("error encryption" + e.getMessage());
e.printStackTrace();
}
}
public void decryptFile(File srcFile, File destFile) {
try (
InputStream is = new FileInputStream(srcFile);
OutputStream out = new FileOutputStream(destFile);
CipherInputStream cis = new CipherInputStream(is, dcipher)
) {
// Extract IV
byte[] iv = new byte[IV_SIZE];
is.read(iv, 0, IV_SIZE);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// Initialize cypher with IV
dcipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = cis.read(buffer)) > 0) {
out.write(buffer, 0, bytesRead);
}
} catch ( InvalidKeyException | InvalidAlgorithmParameterException | IOException e) {
System.out.println("error decr" + e.getMessage());
e.printStackTrace();
}
}
}
package demo;
import java.io.*;
public class Client {
public static void main(String [] args){
File tempFile =null, src = null, dest = null;
try {
tempFile = new File("temp.txt");
src = new File("C:\Users\x\Desktop\test.txt");
dest = new File("C:\Users\x\Desktop\out.txt");
TestEncryption encryption = new TestEncryption("helloworld", 256);
encryption.encryptFile(src, tempFile);
encryption.decryptFile(tempFile, dest);
}
finally {
tempFile.delete();
//src.delete();
//dest.delete();
}
}
}
您的错误是加密时使用流的方式:
对于CipherOutputStream
,必须在最后关闭,因为只有在关闭时才能写入最后的填充。
但是在您的代码中,cipherOutputStream
实例永远不会关闭。因此填充永远不会写入加密文件。
当然,在解密文件时,应该填充的地方没有填充,您得到的是 BadPaddingException
。
因此您应该将加密更改为:
public void encryptFile(File src, File dest) {
try (InputStream inputStream = new FileInputStream(src);
OutputStream outputStream = new FileOutputStream(dest)) {
try (CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, ecipher)) {
// Generating IV.
byte[] iv = new byte[IV_SIZE];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// First write the IV at the beginning of the encrypted file.
outputStream.write(iv, 0, IV_SIZE);
System.out.println("key 0x" + new BigInteger(1, secretKey.getEncoded()).toString(16));
// Initialize cipher with IV
ecipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
// Encrypt input file and write in to output
while ((bytesRead = inputStream.read(buffer)) >= 0) {
cipherOutputStream.write(buffer, 0, bytesRead);
}
}
} catch (InvalidKeyException | InvalidAlgorithmParameterException | IOException e) {
System.out.println("error encryption" + e.getMessage());
e.printStackTrace();
}
}
public void decryptFile(File srcFile, File destFile) {
try (InputStream is = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile)) {
try (CipherInputStream cis = new CipherInputStream(is, dcipher)) {
// Extract IV
byte[] iv = is.readNBytes(IV_SIZE);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// Initialize cypher with IV
dcipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = cis.read(buffer)) >= 0) {
out.write(buffer, 0, bytesRead);
}
}
} catch (InvalidKeyException | InvalidAlgorithmParameterException | IOException e) {
System.out.println("error decr" + e.getMessage());
e.printStackTrace();
}
}
还有一个原因可能是你需要描述的内容,但是传递给方法时参数为null,也会抛出badpaddedException。