注意:稍后再回来讨论,因为我找不到可行的解决方案。手动排空输入流而不是使用 BufferedReaders 似乎没有帮助,因为 inputStream.read() 方法会永久阻止程序。我将 gpg 调用放在一个批处理文件中,并从 Java 调用该批处理文件以仅获得相同的结果。一旦使用解密选项调用 gpg,输入流似乎变得不可访问,从而阻塞了整个程序。当我有更多时间专注于这项任务时,我将不得不回到这一点。与此同时,我将不得不通过其他方式(可能是 BouncyCastle)进行解密。
可能尝试的最后一个选项是调用 cmd.exe,并通过该进程生成的输入流写入命令......
我感谢在这个问题上的帮助。
我已经在这个问题上工作了几天并且没有取得任何进展,所以我想我会在这里寻求帮助。
我正在创建一个简单的程序,它将通过 Java 运行时进程调用 GnuPG。它需要能够加密和解密文件。加密有效,但我在解密文件时遇到了一些问题。每当我尝试解密文件时,该过程都会挂起。exitValue()
总是抛出它是 IllegalThreadStateException 并且程序像它还在等待一样突然出现。这些方法的代码附在下面。该程序的最终目标是解密文件,并在 Java 中解析其内容。
我尝试了三种让 gpgDecrypt 方法工作的方法。第一种方法涉及删除 passphrase-fd 选项并通过 catch 块中的 gpgOutput 流将密码写入 gpg,假设它像通过命令行一样提示输入密码。这不起作用,所以我将密码放在一个文件中并添加了 -passphrase-fd 选项。在这种情况下,程序会无限重复。如果我通过 gpgOutput 流写任何东西,程序就会完成。打印的退出值的值为 2,结果变量将为空白。
第三个选项是 BouncyCastle,但我无法让它识别我的私钥(这可能是一个单独的帖子)。
我用来加密和解密的密钥是由 GnuPG 生成的 4096 位 RSA 密钥。在使用密码短语和密码短语文件的两种情况下,我都尝试将输出通过管道传输到文件> myFile.txt
,但似乎没有任何区别。
以下是 gpgEncrypt、gpgDecrypt 和 getStreamText 方法。自从加密工作以来,我都发布了两者,并且我看不到加密和解密方法之间的执行和处理过程之间的任何明显差异。getStreamText 只是读取流的内容并返回一个字符串。
编辑:快速说明,Windows 环境。如果我复制解密命令输出,它可以通过控制台正常工作。所以我知道该命令是有效的。
public boolean gpgEncrypt(String file, String recipient, String outputFile){
boolean success = true;
StringBuilder gpgCommand = new StringBuilder("gpg --recipient \"");
gpgCommand.append(recipient).append("\" --output \"").append(outputFile).append("\" --yes --encrypt \"");
gpgCommand.append(file).append("\"");
System.out.println("ENCRYPT COMMAND: " + gpgCommand);
try {
Process gpgProcess = Runtime.getRuntime().exec(gpgCommand.toString());
BufferedReader gpgOutput = new BufferedReader(new InputStreamReader(gpgProcess.getInputStream()));
BufferedWriter gpgInput = new BufferedWriter(new OutputStreamWriter(gpgProcess.getOutputStream()));
BufferedReader gpgErrorOutput = new BufferedReader(new InputStreamReader(gpgProcess.getErrorStream()));
boolean executing = true;
while(executing){
try{
int exitValue = gpgProcess.exitValue();
if(gpgErrorOutput.ready()){
String error = getStreamText(gpgErrorOutput);
System.err.println(error);
success = false;
break;
}else if(gpgOutput.ready()){
System.out.println(getStreamText(gpgOutput));
}
executing = false;
}catch(Exception e){
//The process is not yet ready to exit. Take a break and try again.
try {
Thread.sleep(100);
} catch (InterruptedException e1) {
System.err.println("This thread has insomnia: " + e1.getMessage());
}
}
}
} catch (IOException e) {
System.err.println("Error running GPG via runtime: " + e.getMessage());
success = false;
}
return success;
}
public String gpgDecrypt(String file, String passphraseFile){
String result = null;
StringBuilder command = new StringBuilder("gpg --passphrase-fd 0 --decrypt \"");
command.append(file).append("\" 0<\"").append(passphraseFile).append("\"");
System.out.println("DECRYPT COMMAND: " + command.toString());
try {
Process gpgProcess = Runtime.getRuntime().exec(command.toString());
BufferedReader gpgOutput = new BufferedReader(new InputStreamReader(gpgProcess.getInputStream()));
BufferedReader gpgErrorOutput = new BufferedReader(new InputStreamReader(gpgProcess.getErrorStream()));
BufferedWriter gpgInput = new BufferedWriter(new OutputStreamWriter(gpgProcess.getOutputStream()));
boolean executing = true;
while(executing){
try{
if(gpgErrorOutput.ready()){
result = getStreamText(gpgErrorOutput);
System.err.println(result);
break;
}else if(gpgOutput.ready()){
result = getStreamText(gpgOutput);
}
int exitValue = gpgProcess.exitValue();
System.out.println("EXIT: " + exitValue);
executing = false;
}catch(IllegalThreadStateException e){
System.out.println("Not yet ready. Stream status: " + gpgOutput.ready() + ", error: " + gpgErrorOutput.ready());
try {
Thread.sleep(100);
} catch (InterruptedException e1) {
System.err.println("This thread has insomnia: " + e1.getMessage());
}
}
}
} catch (IOException e) {
System.err.println("Unable to execute GPG decrypt command via command line: " + e.getMessage());
}
return result;
}
private String getStreamText(BufferedReader reader) throws IOException{
StringBuilder result = new StringBuilder();
try{
while(reader.ready()){
result.append(reader.readLine());
if(reader.ready()){
result.append("\n");
}
}
}catch(IOException ioe){
System.err.println("Error while reading the stream: " + ioe.getMessage());
throw ioe;
}
return result.toString();
}