我正在尝试构建一个压缩的 Java 程序,然后使用 AES 加密对文件进行加密。但是,我在加密过程中收到以下错误:
Exception in thread "main" java.security.NoSuchAlgorithmException: Cannot find any provider supporting PBKDF2WithHmacSHA256
at java.base/javax.crypto.Cipher.getInstance(Cipher.java:574)
at MyJavaProject.zip.encryptFile(zip.java:75)
at MyJavaProject.zip.main(zip.java:58)
我在下面包含了我的代码。它应该压缩我指向的文件,然后对其进行加密,并保存盐和 IV 的字节,以便稍后解密。我正在使用 Java 16,而我的 JRE 是 JavaSE-12。
class zip {
public static void main(String[] args) throws IOException, InvalidKeyException, NoSuchPaddingException,
NoSuchAlgorithmException, InvalidAlgorithmParameterException, BadPaddingException,
IllegalBlockSizeException, InvalidKeySpecException {
FileInputStream fis = new FileInputStream("texty.txt");
FileOutputStream fos = new FileOutputStream("texty(comp)");
DeflaterOutputStream dos = new DeflaterOutputStream(fos);
int data;
while ((data = fis.read()) != -1) {
dos.write(data);
}
fis.close();
dos.close();
SecureRandom random = new SecureRandom();
byte[] salt = new byte[16];
random.nextBytes(salt);
SecretKey key = getKeyFromPassword("Password", salt.toString());
String algorithm = "AES/CBC/PKCS5Padding";
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
IvParameterSpec Iv = new IvParameterSpec(iv);
encryptFile(algorithm, key, Iv, new File("texty(comp)"), new File("texty(compNenc)"));
FileOutputStream fs = new FileOutputStream(new File("intravenus"));
BufferedOutputStream bos = new BufferedOutputStream(fs);
bos.write(iv);
bos.close();
FileOutputStream fs2 = new FileOutputStream(new File("pepper"));
BufferedOutputStream bos2 = new BufferedOutputStream(fs2);
bos2.write(salt);
bos2.close();
}
public static void encryptFile(String algorithm, SecretKey key, IvParameterSpec iv, File inputFile, File outputFile)
throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
FileInputStream inputStream = new FileInputStream(inputFile);
FileOutputStream outputStream = new FileOutputStream(outputFile);
byte[] buffer = new byte[64];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
byte[] output = cipher.update(buffer, 0, bytesRead);
if (output != null) {
outputStream.write(output);
}
}
byte[] outputBytes = cipher.doFinal();
if (outputBytes != null) {
outputStream.write(outputBytes);
}
inputStream.close();
outputStream.close();
}
public static SecretKey getKeyFromPassword(String password, String salt)
throws NoSuchAlgorithmException, InvalidKeySpecException {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), 65536, 256);
SecretKey secret = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
return secret;
}
}
更新:感谢@that other guy 帮助我解决最初的错误,但现在我有一个新的错误,我还不够先进,无法理解。当我尝试下载为 salt 和 IV 存储的字节并尝试解密文件时,我收到以下错误消息:
Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
at java.base/com.sun.crypto.provider.CipherCore.unpad(CipherCore.java:975)
at java.base/com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:1056)
at java.base/com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:853)
at java.base/com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2091)
at MyJavaProject.unzip.decryptFile(unzip.java:99)
at MyJavaProject.unzip.main(unzip.java:52)
下面列出了我的解密文件代码。如果有人可以提供帮助,我将不胜感激。
class unzip {
public static void main(String[] args)
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException,
NoSuchPaddingException, InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException {
byte[] fileData = new byte[16];
DataInputStream dis = null;
dis = new DataInputStream(new FileInputStream(new File("intravenus")));
dis.readFully(fileData);
if (dis != null) {
dis.close();
}
byte[] iv = fileData;
IvParameterSpec Iv = new IvParameterSpec(iv);
byte[] fileData2 = new byte[16];
DataInputStream dis2 = null;
dis2 = new DataInputStream(new FileInputStream(new File("pepper")));
dis2.readFully(fileData2);
if (dis2 != null) {
dis2.close();
}
byte[] salt = fileData2;
SecretKey key = getKeyFromPassword("Password", salt.toString());
String algorithm = "AES/CBC/PKCS5Padding";
decryptFile(algorithm, key, Iv, new File("texty(compNenc)"), new File("texty(compNdec)"));
// assign Input File : file2 to FileInputStream for reading data
FileInputStream fis = new FileInputStream("texty(compNdec)");
// assign output file: file3 to FileOutputStream for reading the data
FileOutputStream fos = new FileOutputStream("texty(decompNdec)");
// assign inflaterInputStream to FileInputStream for uncompressing the data
InflaterInputStream iis = new InflaterInputStream(fis);
// read data from inflaterInputStream and write it into FileOutputStream
int data;
while ((data = iis.read()) != -1) {
fos.write(data);
}
// close the files
fos.close();
iis.close();
}
public static SecretKey getKeyFromPassword(String password, String salt)
throws NoSuchAlgorithmException, InvalidKeySpecException {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), 65536, 256);
SecretKey secret = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
return secret;
}
public static void decryptFile(String algorithm, SecretKey key, IvParameterSpec iv, File encryptedFile,
File decryptedFile) throws IOException, NoSuchPaddingException, NoSuchAlgorithmException,
InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, key, iv);
FileInputStream inputStream = new FileInputStream(encryptedFile);
FileOutputStream outputStream = new FileOutputStream(decryptedFile);
byte[] buffer = new byte[64];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
byte[] output = cipher.update(buffer, 0, bytesRead);
if (output != null) {
outputStream.write(output);
}
}
byte[] output = cipher.doFinal();
if (output != null) {
outputStream.write(output);
}
inputStream.close();
outputStream.close();
}
}