通过运行时进程在Java中调用GnuPG来加密和解密文件 - Decrypt始终挂起

fra*_*o13 5 java encryption gnupg runtime.exec

注意:稍后再回过头来,因为我无法找到有效的解决方案.手动排出输入流而不是使用BufferedReaders似乎没有帮助,因为inputStream.read()方法永久阻止程序.我将gpg调用放在批处理文件中,并从Java调用批处理文件以获得相同的结果.一旦使用decrypt选项调用gpg,输入流似乎变得不可访问,阻塞整个程序.当我有更多时间专注于这项任务时,我将不得不回到这一点.与此同时,我将不得不通过其他方式(可能是BouncyCastle)来解密.

可能尝试的最后一个选项是调用cmd.exe,并通过该进程生成的输入流编写命令...

我很感谢在这个问题上给予的帮助.


我已经在这个问题上工作了几天而没有取得任何进展,所以我想我会转向这里的exeprtise寻求帮助.

我正在创建一个简单的程序,它将通过Java运行时进程调用GnuPG.它需要能够加密和解密文件.加密有效,但我在解密文件时遇到了一些问题.每当我尝试解密文件时,该过程都会挂起.exitValue()总是抛出它的IllegalThreadStateException,程序突然好像还在等待.这些方法的代码如下.该程序的最终目标是解密文件,并用Java解析它的内容.

我已经尝试了三种方法来使gpgDecrypt方法起作用.第一种方法涉及删除passphrase-fd选项并通过catch块中的gpgOutput流将密码短语写入gpg,假设它正在通过命令行提示密码短语.这不起作用,所以我将密码短语放在一个文件中并添加了-passphrase-fd选项.在这种情况下,程序无限重复.如果我通过gpgOutput流写任何东西,程序将完成.打印的Exit值的值为2,结果变量为空.

第三个选项是BouncyCastle,但我在识别我的私钥时遇到了问题(这可能是一个单独的帖子).

我用来加密和解密的密钥是由GnuPG生成的4096位RSA密钥.在使用密码短语和密码短语文件的两种情况下,我都尝试将输出通过管道传输到文件> myFile.txt,但它似乎没有任何区别.

这是gpgEncrypt,gpgDecrypt和getStreamText方法.我发布了两个,因为加密工作,我看不出我如何执行和处理加密和解密方法之间的过程之间的任何明显差异.getStreamText只读取流的内容并返回一个字符串.

编辑:快速注释,Windows环境.如果我复制decrypt命令输出,它可以通过控制台正常工作.所以我知道命令是有效的.


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();
}
Run Code Online (Sandbox Code Playgroud)

Nic*_*sky 1

您是否尝试过从命令行而不是 Java 代码运行该命令?当 GnuPG 等待控制台输出时,“仅用于您的眼睛”选项可能会出现问题。