Итак, у меня есть очень простая команда openssl, которая была предоставлена мне openssl smime -encrypt -binary -aes-256-cbc -in $inPath -out $encryptedPath -outform DER $pubCert
, эта команда также работает правильно и выводит зашифрованный файл.Мне нужно использовать эквивалент этой команды в Java-приложении, желательно без вызова процесса и использования самого openssl (только потому, что я чувствую, что это, вероятно, плохая практика).
Я довольно много исследовал, и там естьКажется, я не могу найти ничего подобного. Я пробовал несколько вещей, и большинство из них, похоже, не работают.Странная вещь ... я могу получить простую строку "Hello World" для шифрования с использованием кода, который я написал (хотя я не верю, что он шифровал это правильно, потому что у меня был установлен шифр "RSA" not "AES "), но когда байтовый массив пришел из файла, он молча потерпел неудачу и просто записал 0 байтов.Прямо сейчас это то, на что похож мой код.
Cipher aes = Cipher.getInstance("RSA");
CertificateFactory certF = CertificateFactory.getInstance("X.509");
File public_cert = new File( getClass().getClassLoader().getResource("public.crt").getFile());
FileInputStream certIS = new FileInputStream(public_cert);
X509Certificate cert = (X509Certificate) certF.generateCertificate(certIS);
certIS.close();
aes.init(Cipher.ENCRYPT_MODE, cert);
File tarGz = new File("C:\\volatile\\generic.tar.gz");
FileInputStream fis = new FileInputStream(tarGz);
byte[] tarGzBytes = FileUtils.readFileToByteArray(tarGz);
tarGzBytes = "Hello World".getBytes();
ByteArrayInputStream bais = new ByteArrayInputStream("Hello World".getBytes());
File encFile = new File("C:\\volatile\\generic.tar.gz.enc");
FileOutputStream enc = new FileOutputStream(encFile);
CipherOutputStream cos = new CipherOutputStream(enc, aes);
cos.write(tarGzBytes);
//IOUtils.copy(fis, cos);
//IOUtils.copy(bais, cos);
cos.flush();
cos.close();
Так что это работает, и шифрует небольшой файл с Hello World
зашифрованным в нем.Я не верю, что это AES-256-CBC, и он не работает, когда я использую FileUtils.readFileToByteArray(tarGz)
, хотя результирующий байтовый массив в отладчике имеет правильный размер около 94 МБ.Мне кажется странным, что он работает с "Hello World".toByteArray()
, а не FileUtils.readAllBytes(tarGz)
.Также, как примечание: ByteArrayInputStream
с использованием IOUtils.copy
работает, тогда как версия FileInputStream
также записывает 0 байтов.
Кроме того, когда я установил режим шифрования на AES/CBC/PKCS5Padding
(потому что я нашел в сети что-то, предлагающее установить это значение, и это больше похоже на то, что я хочу), я получаю следующее сообщение об ошибке:
java.security.InvalidKeyException: No installed provider supports this key: sun.security.rsa.RSAPublicKeyImpl
at javax.crypto.Cipher.chooseProvider(Cipher.java:892)
at javax.crypto.Cipher.init(Cipher.java:1724)
~~~~
Если у кого-то есть какие-либо предложения, или если мне нужно предоставить больше информации, пожалуйста, дайте мне знать.Я довольно застрял прямо сейчас, и сейчас я спорю о написании скрипта, который просто запускает команду openssl и запускает этот скрипт из Java ...
Заключение
После прочтения @ dave-Ответ thompson-085 Я понял, что была действительно веская причина, почему я не мог найти то, что я хотел сделать.Поэтому я решил пойти дальше и просто вызвать openssl
процесс из Java с помощью компоновщика процессов.Я был в состоянии воссоздать команду openssl сверху как Процесс в Java, запустить ее и запустить с помощью следующего кода:
File cert = new File(getClass().getClassLoader().getResource("public.crt").getFile());
ProcessBuilder openSslBuilder = new ProcessBuilder("openssl", "smime", "-encrypt", "-binary",
"-aes-256-cbc", "-in", "C:\\volatile\\generic.tar.gz", "-out",
"C:\\volatile\\generic.tar.gz.enc", "-outform", "DER", cert.getPath());
Process openssl = openSslBuilder.start();
openssl.waitFor();
System.out.println(openssl.exitValue());
openssl.destroy();
Надеюсь, это поможет кому-то еще, кто хочет попробовать это и, возможно,сэкономить кому-то кучу времени!