Llamar a GnuPG en Java a través de un proceso de tiempo de ejecución para cifrar y descifrar archivos: descifrar siempre se bloquea

NOTA: Volviendo a esto más tarde, ya que no he podido encontrar una solución que funcione. Drenar las secuencias de entrada manualmente en lugar de usar BufferedReaders no parece ayudar ya que el método inputStream.read () bloquea permanentemente el programa. Coloqué la llamada gpg en un archivo por lotes y llamé al archivo por lotes desde Java para obtener el mismo resultado. Una vez que se llama a gpg con la opción de descifrado, la secuencia de entrada parece ser inaccesible, bloqueando todo el programa. Tendré que volver a esto cuando tenga más tiempo para concentrarme en la tarea. Mientras tanto, tendré que hacer que el descifrado funcione por otros medios (probablemente BouncyCastle).

La última opción para probar probablemente es llamar a cmd.exe y escribir el comando a través de la secuencia de entrada generada por ese proceso ...

Agradezco la asistencia en este tema.

He estado trabajando en este problema durante un par de días y no he hecho ningún progreso, así que pensé en recurrir al experto aquí para obtener ayuda.

Estoy creando un programa simple que llamará a GnuPG a través de un proceso de tiempo de ejecución Java. Necesita poder cifrar y descifrar archivos. El cifrado funciona, pero tengo algunos problemas para descifrar archivos. Cada vez que intento descifrar un archivo, el proceso se bloquea.exitValue() siempre arroja su IllegalThreadStateException y el programa funciona como si todavía estuviera esperando. El código para estos métodos se adjunta a continuación. El objetivo final del programa es descifrar el archivo y analizar su contenido en Java.

He intentado tres enfoques para que el método gpgDecrypt funcione. El primer enfoque implicaba eliminar la opción passphrase-fd y escribir la frase de contraseña en gpg a través de la secuencia gpgOutput en el bloque catch, suponiendo que solicitaba la frase de contraseña como lo haría a través de la línea de comando. Esto no funcionó, así que puse la frase de contraseña en un archivo y agregué la opción -passphrase-fd. En este caso, el programa se repite infinitamente. Si escribo algo a través de la secuencia gpgOutput, el programa se completará. El valor de salida impreso tendrá un valor de 2 y la variable de resultado estará en blanco.

La tercera opción es BouncyCastle, pero tengo problemas para que reconozca mi clave privada (que probablemente sea una publicación separada por completo).

Las claves que estoy usando para cifrar y descifrar son claves RSA de 4096 bits, generadas por GnuPG. En ambos casos, usando la frase de contraseña y el archivo de frase de contraseña, he intentado canalizar la salida a un archivo a través de> myFile.txt, pero no parece hacer ninguna diferencia.

Aquí están los métodos gpgEncrypt, gpgDecrypt y getStreamText. Publiqué ambos ya que el cifrado funciona, y no puedo ver ninguna diferencia evidente entre cómo estoy ejecutando y manejando el proceso entre los métodos de cifrado y descifrado. getStreamText solo lee el contenido de las secuencias y devuelve una cadena.

EDITAR: Nota rápida, entorno de Windows. Si copio la salida del comando descifrar, funciona a través de la consola bien. Entonces sé que el comando es válido.

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();
}

Respuestas a la pregunta(6)

Su respuesta a la pregunta