2010-12-06 9 views
5

HINWEIS: Ich komme später zurück, da ich keine funktionierende Lösung gefunden habe. Das manuelle Löschen der Eingabeströme anstelle der Verwendung von BufferedReaders scheint nicht hilfreich zu sein, da die Methode inputStream.read() das Programm permanent blockiert. Ich legte den GPG-Aufruf in eine Batch-Datei und rief die Batch-Datei von Java, um nur das gleiche Ergebnis zu erhalten. Sobald gpg mit der Entschlüsselungsoption aufgerufen wird, scheint der Eingabestream nicht mehr zugänglich zu sein und blockiert das gesamte Programm. Ich muss darauf zurückkommen, wenn ich mehr Zeit habe, mich auf die Aufgabe zu konzentrieren. In der Zwischenzeit muss ich die Entschlüsselung mit anderen Mitteln (wahrscheinlich BouncyCastle) arbeiten lassen.Aufruf von GnuPG in Java über einen Laufzeitprozess zum Verschlüsseln und Entschlüsseln von Dateien - Entschlüsseln bleibt immer hängen

Die letzte Option wahrscheinlich versuchen, ist cmd.exe zu nennen, und den Befehl über den Eingangsstrom durch dieses Verfahren erzeugte schreiben ...

ich die Hilfe zu diesem Thema zu schätzen wissen.


Ich habe für ein paar Tage an diesem Problem gearbeitet und haben keine Fortschritte gemacht, so dass ich dachte, dass ich auf die exeprtise für etwas Hilfe hier drehen würde.

Ich erstelle ein einfaches Programm, das GnuPG über einen Java-Laufzeitprozess aufruft. Es muss in der Lage sein, Dateien zu verschlüsseln und zu entschlüsseln. Verschlüsselung funktioniert, aber ich habe einige Probleme beim Entschlüsseln von Dateien. Immer wenn ich versuche, eine Datei zu entschlüsseln, hängt der Prozess. exitValue() löst immer IllegalThreadStateException aus und das Programm tuckert weiter, als würde es immer noch warten. Der Code für diese Methoden ist unten aufgeführt. Das ultimative Ziel des Programms ist es, die Datei zu entschlüsseln und ihre Inhalte in Java zu parsen.

Ich habe drei Ansätze ausprobiert, um die gpgDecrypt-Methode zum Laufen zu bringen. Der erste Ansatz beinhaltete das Entfernen der Passphrase-fd-Option und das Schreiben der Passphrase in gpg über den gpgOutput-Stream im catch-Block, wobei angenommen wurde, dass die Passphrase wie über die Befehlszeile abgefragt wurde. Das hat nicht funktioniert, also habe ich die Passphrase in eine Datei geschrieben und die Option -passphrase-fd hinzugefügt. In diesem Fall wird das Programm unendlich wiederholt. Wenn ich irgendetwas über den gpgOutput-Stream schreibe, wird das Programm beendet. Der ausgegebene Exit-Wert hat den Wert 2, und die Ergebnisvariable ist leer.

Die dritte Option ist BouncyCastle, aber ich habe Probleme, es meinen privaten Schlüssel zu erkennen (was wahrscheinlich ein separater Beitrag alle zusammen ist).

Die Schlüssel, die ich zum Verschlüsseln und Entschlüsseln verwende, sind 4096-Bit-RSA-Schlüssel, die von GnuPG generiert werden. In beiden Fällen, in denen ich die Passphrase und die Passphrase-Datei verwende, habe ich versucht, die Ausgabe über > myFile.txt in eine Datei zu leiten, aber es scheint keinen Unterschied zu machen.

Hier sind die Methoden gpgEncrypt, gpgDecrypt und getStreamText. Ich habe beide gepostet, seit die Verschlüsselung funktioniert, und ich kann keine eklatanten Unterschiede zwischen der Ausführung und der Verarbeitung des Prozesses zwischen den Verschlüsselungs- und Entschlüsselungsmethoden feststellen. getStreamText liest nur den Inhalt der Streams und gibt eine Zeichenfolge zurück.

EDIT: Schnelle Notiz, Windows-Umgebung. Wenn ich die Ausgabe des Entschlüsselungsbefehls kopiere, funktioniert es über die Konsole einwandfrei. Ich weiß also, dass der Befehl gültig ist.


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

Ich habe eine Menge Batch/Script-Aufrufe von Java gemacht. Ich kann Ihnen eines sagen: Der Versuch, einen String mit Leerzeichen zu erstellen, ist ein Rezept für ein Desaster. Rufen Sie ** NIEMALS ** die Methode * Runtime.getRuntime() .exec (String) * auf. Was Sie ** SOLLTEN ** ist, teilen Sie Ihre Zeichenfolge und rufen Sie die * Runtime.getRuntime() .Exec (String []) * -Methode. Beachten Sie, dass ich nicht sage, dass es das Problem lösen soll, das Sie hier haben: Alles, was ich sage, ist, dass Sie irgendwann leiden werden, wenn Sie Charge/Skripte so aufrufen, wie Sie es gerade tun. – SyntaxT3rr0r

+0

Danke für die Eingabe. Ich werde das umgestalten. Unabhängig davon, ob es das Problem behebt oder nicht, stimme ich zu, dass es getan werden muss. – framauro13

+0

Haben Sie irgendwelche Antworten gefunden, bin ich auch auf dasselbe gestoßen! Ich fing an zu codieren, als ich dein Beispiel sah, als ich das [stream gobbler] (http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=4#codewrap144) Problem sah, das ich benutzt habe auch. Aber dieses hängende Problem blieb bestehen, als es bereits eine Datei gab und i gpg.exe darauf wartete, dass der Benutzer 'y ' schlug. Aber der irritierende Teil war die Aufforderung zu wählen, dass y/N niemals in der Konsole erscheint (Stream Gobbler), also kann ich das programmatisch nicht handhaben. Der Stream-Gobbler zeigt an, ob gpg.exe erfolgreich abgeschlossen wurde. –

Antwort

1

Haben Sie versucht, diesen Befehl aus Befehlszeile auszuführen, nicht von Java-Code? Es kann ein Problem mit der Option "Nur für Ihre Augen" geben, wenn GnuPG auf die Konsolenausgabe wartet.

+0

Der von der Anwendung generierte Befehl läuft einwandfrei, wenn ich ihn über die Befehlszeile ausführe. Ich kann versuchen, es in eine Batch-Datei zu verpacken und stattdessen die Batch-Datei aufzurufen. – framauro13

1

Dies kann oder kann nicht das Problem sein (in der Entschlüsselungsfunktion)

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

Sie sind das Ergebnis von getInputStream zweimal gewickelt wird. Offensichtlich sollte gpgErrorOutput den Fehlerstream, nicht den Eingabestream, umhüllen.

+1

Haben Sie auch http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html gelesen? Eine zuverlässige Verwendung von Runtime.exec benötigt Threads, die die Ausgabe des Programms lesen. –

+0

Danke, das habe ich total vermisst. Lustig, wie man stundenlang Stunden damit verbringen kann, APIs zu lesen, Prozesse zu entwerfen und sich Gedanken über Effizienz zu machen und einen dummen Fehler wie diesen zu machen :) – framauro13

+0

Ich habe den Code aktualisiert, um den richtigen Stream einzubinden ... leider bleibt das Hängen bestehen. – framauro13

0
int exitValue = gpgProcess.exitValue(); 

// es Verfahren gibt hat Ausnahme nicht verlassen

0

Es funktionierte für mich, wenn ich den Entschlüsselungs-Befehl mit folgenden Befehl ersetzen

gpg --output decrypted_file --batch --passphrase "passphrase goes here" --decrypt encrypted_file 
3

ich vergessen, wie Sie es in Java behandeln, da sind 100 Methoden dafür. Aber ich mit Entschlüsselungs Befehl festsaß selbst war es sehr hilfreich, wenn Sie nicht diese Zitate alle haben müssen und wenn Sie es wünschen, eine große Datei zu entschlüsseln, geht es wie folgt aus:

gpg --passphrase-fd 0 --output yourfile.txt --decrypt /encryptedfile.txt.gpg/ 0</passwrdfile.txt 
1

ich eher zufällig auf diesen Thread heute, weil ich genau das gleiche Problem hatte, was das Programm betrifft. Camerons Thread von oben enthält die Lösung, dass Sie den InputStream aus Ihrem Prozess entfernen müssen. Wenn nicht, füllt sich der Stream und hängt. Einfach hinzufügen

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

Vor der Überprüfung der exitValue behoben es für mich.