5

注意:稍后再回来讨论,因为我找不到可行的解决方案。手动排空输入流而不是使用 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();
}
4

7 回答 7

3

我忘记了你在 Java 中是如何处理它的,有 100 种方法。但是我被解密命令本身困住了,它非常有帮助,虽然你不需要所有这些引号,如果你想解密一个大文件,它是这样的:

gpg --passphrase-fd 0 --output yourfile.txt --decrypt /encryptedfile.txt.gpg/ 0</passwrdfile.txt
于 2011-10-27T16:05:15.490 回答
1

您是否尝试过从命令行而不是 Java 代码运行该命令?当 GnuPG 将等待控制台输出时,“for your eyes only”选项可能存在问题。

于 2010-12-06T14:00:56.193 回答
1

这可能是也可能不是问题(在解密功能中)

    BufferedReader gpgOutput = new BufferedReader(new InputStreamReader(gpgProcess.getInputStream()));
    BufferedReader gpgErrorOutput = new BufferedReader(new InputStreamReader(gpgProcess.getInputStream()));
    BufferedWriter gpgInput = new BufferedWriter(new OutputStreamWriter(gpgProcess.getOutputStream()));

您正在包装getInputStream两次的结果。显然gpgErrorOutput应该包装错误流,而不是输入流。

于 2010-12-06T14:01:50.677 回答
1

我今天偶然发现了这个线程,因为就程序挂起而言,我遇到了完全相同的问题。上面的 Cameron 线程包含解决方案,即您必须从进程中排出 inputStream。如果不这样做,则流会填满并挂起。只需添加

String line = null;
while ( (line = gpgOutput.readLine()) != null ) {
     System.out.println(line);
}

在检查 exitValue 之前为我修复了它。

于 2013-02-21T14:08:48.560 回答
0

当我用以下命令替换解密命令时,它对我有用

gpg --output decrypted_file --batch --passphrase "passphrase goes here" --decrypt encrypted_file
于 2010-12-29T09:58:38.097 回答
0
int exitValue = gpgProcess.exitValue();

// 它给进程没有退出异常

于 2010-12-28T13:09:01.427 回答
0

以下代码适用于 GNUPG 2.1.X

public static 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;
}

// gpg --pinentry-mode=loopback --passphrase "siv_test" -d -o
// "sample_enc_data_op.txt" "sample_enc_data_input.gpg"

public static String gpgDecrypt(String file, String passphrase,
        String outputfile) {
    String result = null;
    StringBuilder command = new StringBuilder(
            "gpg --pinentry-mode=loopback --passphrase \"");
    command.append(passphrase).append("\" -d -o \"").append(outputfile)

    .append("\" --yes \"").append(file)

    .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);
                }
                String line = null;
                while ((line = gpgOutput.readLine()) != null) {
                    System.out.println(line);
                }
                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 static 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();
}
于 2020-10-08T07:08:50.320 回答