Давайте упростим это и используем функции, недавно появившиеся в классах InputStream
Java:
public static void encrypt(RSAPublicKey publicKey) throws Exception {
try (FileOutputStream out = new FileOutputStream("dataFile" + ".enc")) {
// --- RSA using PKCS#1 v1.5 padding
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// --- AES key generator
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
SecretKey skey = kgen.generateKey();
// --- write encrypted AES key
byte[] encryptedSKey = cipher.doFinal(skey.getEncoded());
out.write(encryptedSKey);
// --- Initialization vector 16 byte
SecureRandom srandom = new SecureRandom();
byte[] iv = new byte[128/8];
srandom.nextBytes(iv);
IvParameterSpec ivspec = new IvParameterSpec(iv);
// --- write IV
out.write(iv);
// --- initialize AES cipher
Cipher ci = Cipher.getInstance("AES/CBC/PKCS5Padding");
ci.init(Cipher.ENCRYPT_MODE, skey, ivspec);
// --- convert file by copying to memory
try (FileInputStream in = new FileInputStream("dataFile.xml")) {
byte[] buffer = in.readAllBytes();
byte[] encryptedData = ci.doFinal(buffer);
out.write(encryptedData);
}
}
}
public static void decrypt(RSAPrivateKey privateKey) throws Exception {
try (FileInputStream in = new FileInputStream("dataFile" + ".enc")) {
// --- RSA using PKCS#1 v1.5 padding
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// --- read encrypted AES key
byte[] encryptedSKey = in.readNBytes(determineEncryptionSizeInBytes(privateKey));
byte[] decryptedSKey = cipher.doFinal(encryptedSKey);
SecretKey skey = new SecretKeySpec(decryptedSKey, "AES");
// --- Initialization vector 16 byte
byte[] iv = in.readNBytes(128 / Byte.SIZE);
IvParameterSpec ivspec = new IvParameterSpec(iv);
// --- initialize AES cipher
Cipher ci = Cipher.getInstance("AES/CBC/PKCS5Padding");
ci.init(Cipher.DECRYPT_MODE, skey, ivspec);
// --- convert file by copying to memory
File outputDataFile = new File("dataFile.xml2");
try (FileOutputStream out = new FileOutputStream(outputDataFile)) {
byte[] buffer = in.readAllBytes();
byte[] decryptedData = ci.doFinal(buffer);
out.write(decryptedData);
}
}
}
private static int determineEncryptionSizeInBytes(RSAPrivateKey privateKey) {
return (privateKey.getModulus().bitLength() + Byte.SIZE - 1) / Byte.SIZE;
}
public static void main(String[] args) throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(384 * Byte.SIZE);
KeyPair pair = kpg.generateKeyPair();
encrypt((RSAPublicKey) pair.getPublic());
decrypt((RSAPrivateKey) pair.getPrivate());
}
Как видите, код теперь очень похож на зеркальное отображение. Я просто скопировал код шифрования и затем внес в него изменения. Как вы можете видеть, теперь он использует меньше классов, полагаясь на InputStream#readAllBytes()
(начиная с Java 9) и InputStream#readNBytes()
(начиная с Java 11).
Обратите внимание, что обычно вы хотите передавать файл, используя меньший буфер. Поскольку весь открытый текст и зашифрованный текст в настоящее время буферизуются, ваше приложение использует гораздо больше памяти, чем требуется. Для шифрования данных с использованием потоков вы можете использовать CipherInputStream
и CipherOutputStream
.
Нет необходимости говорить, что обработка исключений нуждается в улучшении, я просто нашел лучший способ решить вашу текущую проблему. Пожалуйста, взгляните еще раз, когда у вас все работает (работайте, работайте правильно, оптимизируйте).