AES暗号化を使用してファイルを圧縮してから暗号化するJavaプログラムを構築しようとしています。ただし、暗号化プロセス中に次のエラーが発生します。
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に感謝しますが、今では理解するのに十分なほど進んでいない新しいエラーがあります。ソルトと 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();
}
}