注意:我将稍后回来,因为我一直找不到可行的解决方案。手动排除输入流而不是使用BufferedReaders似乎没有帮助,因为inputStream.read()方法会永久阻塞程序。我将gpg调用放在批处理文件中,并从Java中调用批处理文件,结果仍然相同。一旦使用解密选项调用gpg,输入流似乎变得无法访问,阻塞整个程序。我必须在有更多时间专注于任务时再回来解决这个问题。与此同时,我必须通过其他方式使解密工作(可能是BouncyCastle)。
最后尝试的选择可能是调用cmd.exe,并通过该进程生成的输入流编写命令...
感谢您对此问题的协助。
我已经为这个问题工作了几天,但没有取得任何进展,所以我想向这里的专家寻求帮助。
我正在创建一个简单的程序,该程序将通过Java运行时进程调用GnuPG。它需要能够加密和解密文件。加密起作用,但是我在解密文件时遇到了一些问题。每当我尝试解密文件时,进程都会挂起。exitValue()
总是抛出IllegalThreadStateException,程序会像仍在等待一样运行。这些方法的代码如下所示。程序的最终目标是解密该文件,并在Java中解析其内容。
我尝试了三种方法来使gpgDecrypt方法工作。第一种方法涉及删除passphrase-fd选项,并通过catch块中的gpgOutput流将passphrase写入gpg,假设它像通过命令行那样提示输入passphrase。这没用,所以我将passphrase放入文件中并添加了-passphrase-fd选项。在这种情况下,程序会无限重复。如果我通过gpgOutput流写任何内容,程序将完成。打印的Exit值将具有2的值,而结果变量将为空白。
第三个选择是BouncyCastle,但我无法让它识别我的私钥(这可能是一个单独的帖子)。
我用于加密和解密的密钥是由GnuPG生成的4096位RSA密钥。在使用passphrase和passphrase文件的两种情况下,我都尝试通过> 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();
}