2013-02-21 24 views
10

Pozwól mi zacząć od stwierdzenia, że ​​jestem niezmiernie nowy w tym wszystkim. Próbuję użyć gpg z poziomu Javy w celu odszyfrowania zaszyfrowanego pliku.Uzyskiwanie deszyfrowania GPG do pracy w Javie (Bouncy Castle)

Co robiłem z powodzeniem:

  • Gdyby kolega zaszyfrować plik, używając swojego klucza publicznego i klucza prywatnego i jego powodzeniem rozszyfrował go.

  • Went inny sposób

  • miał inny kolega starają się odszyfrować plik, który nie był dla niego nie (zgodnie z oczekiwaniami)

Mój klucz został wygenerowany w ten sposób ...

(gpg --version mi mówi, używam 1.4.5 i używam nadmuchiwany zamek 1,47)

gpg --gen-magicznych

Wybierz opcję "DSA i Elgamal (domyślnie)"

Wypełnij pozostałe pola i wygeneruj klucz.

Plik został zaszyfrowany przy użyciu mojego klucza publicznego i tajnego klucza innego użytkownika. Chcę ją odszyfrować. Napisałem następujący kod Java, aby to osiągnąć. Używam kilku przestarzałych metod, ale nie mogę wymyślić, jak poprawnie wdrożyć metody fabryczne wymagane do użycia nie-przestarzałych wersji, więc jeśli ktoś ma pomysł na implementacje tych, których powinienem używać, byłby to miły bonus.

Security.addProvider(new BouncyCastleProvider()); 

     PGPSecretKeyRingCollection secretKeyRing = new PGPSecretKeyRingCollection(new FileInputStream(new File("test-files/secring.gpg"))); 
     PGPSecretKeyRing pgpSecretKeyRing = (PGPSecretKeyRing) secretKeyRing.getKeyRings().next(); 
     PGPSecretKey secretKey = pgpSecretKeyRing.getSecretKey(); 
     PGPPrivateKey privateKey = secretKey.extractPrivateKey("mypassword".toCharArray(), "BC"); 

     System.out.println(privateKey.getKey().getAlgorithm()); 
     System.out.println(privateKey.getKey().getFormat()); 

     PGPObjectFactory pgpF = new PGPObjectFactory(
    new FileInputStream(new File("test-files/test-file.txt.gpg"))); 
     Object pgpObj = pgpF.nextObject(); 
     PGPEncryptedDataList encryptedDataList = (PGPEncryptedDataList) pgpObj; 

     Iterator objectsIterator = encryptedDataList.getEncryptedDataObjects(); 

     PGPPublicKeyEncryptedData publicKeyEncryptedData = (PGPPublicKeyEncryptedData) objectsIterator.next(); 
     InputStream inputStream = publicKeyEncryptedData.getDataStream(privateKey, "BC"); 

Więc kiedy uruchomić ten kod Uczę się, że mój algorytm i format są następujące dla mojego tajnego klucza:

Algorytm: DSA Format: PKCS # 8

A potem rozkłada na ostatnia linia:

Exception in thread "main" org.bouncycastle.openpgp.PGPException: error setting asymmetric cipher 
at org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder.decryptSessionData(Unknown Source) 
at org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder.access$000(Unknown Source) 
at org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder$2.recoverSessionData(Unknown Source) 
at org.bouncycastle.openpgp.PGPPublicKeyEncryptedData.getDataStream(Unknown Source) 
at org.bouncycastle.openpgp.PGPPublicKeyEncryptedData.getDataStream(Unknown Source) 
at org.bouncycastle.openpgp.PGPPublicKeyEncryptedData.getDataStream(Unknown Source) 
at org.bouncycastle.openpgp.PGPPublicKeyEncryptedData.getDataStream(Unknown Source) 
at TestBouncyCastle.main(TestBouncyCastle.java:74) 

Spowodowany przez: java.security.InvalidKeyException: nieznany typ klucz przeszedł do ElGamal na org.bouncyc astle.jcajce.provider.asymmetric.elgamal.CipherSpi.engineInit (Nieznane źródło) at org.bouncycastle.jcajce.provider.asymmetric.elgamal.CipherSpi.engineInit (Nieznane źródło) na javax.crypto.Cipher.init (DashoA13 * ..) na javax.crypto.Cipher.init (DashoA13 * ..) ... 8 więcej

Jestem otwarty na wiele sugestii tutaj, ze „nie używać GPG, użyj zamiast x "do" nie używaj dmuchanego zamku, użyj x zamiast "do dowolnego miejsca pomiędzy. Dzięki!

Odpowiedz

2

Zdecydowałem się pójść ze znacznie innego podejścia, które jest zrezygnować z korzystania z bouncy całkowicie zamienię i po prostu użyj procesu runtime. Dla mnie to rozwiązanie działa i całkowicie usuwa złożoność otaczającego nadmuchiwany zamek:

String[] gpgCommands = new String[] { 
     "gpg", 
     "--passphrase", 
     "password", 
     "--decrypt", 
     "test-files/accounts.txt.gpg" 
}; 

Process gpgProcess = Runtime.getRuntime().exec(gpgCommands); 
BufferedReader gpgOutput = new BufferedReader(new InputStreamReader(gpgProcess.getInputStream())); 
BufferedReader gpgError = new BufferedReader(new InputStreamReader(gpgProcess.getErrorStream())); 

Po zrobieniu, że trzeba pamiętać, aby opróżnić swój strumień wejściowy jako Twój proces execing lub program będzie prawdopodobnie wiszą w zależności od tego, ile Zyskujesz wynik. Zobacz moją odpowiedź w tym wątku (a także Camerona Skinnera i Matthew Wilsona, którzy dostali mnie na właściwej ścieżce) dla nieco więcej kontekstu: Calling GnuPG in Java via a Runtime Process to encrypt and decrypt files - Decrypt always hangs

+1

+1 Ewwwwwwwwwwwwwwww;) –

+9

-1 Z oczywistych powodów. Ponadto hasło może być widoczne dla każdego, kto przegląda listę aktywnych procesów podczas połączenia i może również znaleźć się w dzienniku systemowym. – user359996

1

Pierwszy wynik: Google to this. Wygląda na to, że próbujesz odszyfrować dane ElGamal, ale nie przekazujesz klucza ElGamal.

Istnieją dwa proste możliwości:

  • Twoja kolekcja brelok ma wiele breloki.
  • Twoja brelok ma podklucze.

Wybrałeś DSA z szyfrowaniem ElGamal, więc podejrzewam co najmniej drugie: podklucze są podpisane przez klucz główny; ElGamal nie jest algorytmem podpisywania (nie wiem, czy DSA i ElGamal mogą używać tego samego klucza, ale ogólnie uważa się, że dobrym pomysłem jest użycie różnych kluczy do różnych celów).

Myślę, że chcesz coś takiego (również secretKeyRing prawdopodobnie powinien być przemianowany na secretKeyRingCollection):

PGPSecretKey secretKey = secretKeyRing.getSecretKey(publicKeyEncryptedData.getKeyID()); 
+0

Dzięki za odpowiedź. Zgadzam się na nazewnictwo. Mój klucz zdecydowanie ma klucz podrzędny (przynajmniej kiedy patrzę na niego za pomocą gpg - listy-kluczy). Ale na pewno mogę odszyfrować, używając go na linii poleceń. Co tu mam? – Craig

+0

Czy klucz ElGamal jest podkluczem? –

+0

Hi tc. Postanowiłem przejść z innym podejściem do deszyfrowania gpg w java. Naprawdę doceniam odpowiedź, ale dla mnie jest łatwiejsze rozwiązanie, które opiszę w odpowiedzi poniżej. – Craig

7

Jeśli ktoś jest zainteresowany, aby wiedzieć, jak szyfrować i odszyfrowywać pliki gpg za pomocą sprężynowania biblioteka zamek OpenPGP, sprawdź poniższy kod java:

poniżej są 4 metody idziesz potrzebować:

Sposób poniżej odczyta i zaimportować klucz tajny z .asc pliku:

public static PGPSecretKey readSecretKeyFromCol(InputStream in, long keyId) throws IOException, PGPException { 
    in = PGPUtil.getDecoderStream(in); 
    PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(in, new BcKeyFingerprintCalculator()); 

    PGPSecretKey key = pgpSec.getSecretKey(keyId); 

    if (key == null) { 
     throw new IllegalArgumentException("Can't find encryption key in key ring."); 
    } 
    return key; 
} 

The bel ow metoda będzie czytać i zaimportować klucz publiczny z .asc pliku:

@SuppressWarnings("rawtypes") 
    public static PGPPublicKey readPublicKeyFromCol(InputStream in) throws IOException, PGPException { 
     in = PGPUtil.getDecoderStream(in); 
     PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(in, new BcKeyFingerprintCalculator()); 
     PGPPublicKey key = null; 
     Iterator rIt = pgpPub.getKeyRings(); 
     while (key == null && rIt.hasNext()) { 
      PGPPublicKeyRing kRing = (PGPPublicKeyRing) rIt.next(); 
      Iterator kIt = kRing.getPublicKeys(); 
      while (key == null && kIt.hasNext()) { 
       PGPPublicKey k = (PGPPublicKey) kIt.next(); 
       if (k.isEncryptionKey()) { 
        key = k; 
       } 
      } 
     } 
     if (key == null) { 
      throw new IllegalArgumentException("Can't find encryption key in key ring."); 
     } 
     return key; 
    } 

poniższej 2 metod do odszyfrowywania i szyfrowania plików GPG:

public void decryptFile(InputStream in, InputStream secKeyIn, InputStream pubKeyIn, char[] pass) throws IOException, PGPException, InvalidCipherTextException { 
     Security.addProvider(new BouncyCastleProvider()); 

     PGPPublicKey pubKey = readPublicKeyFromCol(pubKeyIn); 

     PGPSecretKey secKey = readSecretKeyFromCol(secKeyIn, pubKey.getKeyID()); 

     in = PGPUtil.getDecoderStream(in); 

     JcaPGPObjectFactory pgpFact; 


     PGPObjectFactory pgpF = new PGPObjectFactory(in, new BcKeyFingerprintCalculator()); 

     Object o = pgpF.nextObject(); 
     PGPEncryptedDataList encList; 

     if (o instanceof PGPEncryptedDataList) { 

      encList = (PGPEncryptedDataList) o; 

     } else { 

      encList = (PGPEncryptedDataList) pgpF.nextObject(); 

     } 

     Iterator<PGPPublicKeyEncryptedData> itt = encList.getEncryptedDataObjects(); 
     PGPPrivateKey sKey = null; 
     PGPPublicKeyEncryptedData encP = null; 
     while (sKey == null && itt.hasNext()) { 
      encP = itt.next(); 
      secKey = readSecretKeyFromCol(new FileInputStream("PrivateKey.asc"), encP.getKeyID()); 
      sKey = secKey.extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(pass)); 
     } 
     if (sKey == null) { 
      throw new IllegalArgumentException("Secret key for message not found."); 
     } 

     InputStream clear = encP.getDataStream(new BcPublicKeyDataDecryptorFactory(sKey)); 

     pgpFact = new JcaPGPObjectFactory(clear); 

     PGPCompressedData c1 = (PGPCompressedData) pgpFact.nextObject(); 

     pgpFact = new JcaPGPObjectFactory(c1.getDataStream()); 

     PGPLiteralData ld = (PGPLiteralData) pgpFact.nextObject(); 
     ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 

     InputStream inLd = ld.getDataStream(); 

     int ch; 
     while ((ch = inLd.read()) >= 0) { 
      bOut.write(ch); 
     } 

     //System.out.println(bOut.toString()); 

     bOut.writeTo(new FileOutputStream(ld.getFileName())); 
     //return bOut; 

    } 

    public static void encryptFile(OutputStream out, String fileName, PGPPublicKey encKey) throws IOException, NoSuchProviderException, PGPException { 
     Security.addProvider(new BouncyCastleProvider()); 

     ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 

     PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(PGPCompressedData.ZIP); 

     PGPUtil.writeFileToLiteralData(comData.open(bOut), PGPLiteralData.BINARY, new File(fileName)); 

     comData.close(); 

     PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(new BcPGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.TRIPLE_DES).setSecureRandom(new SecureRandom())); 

     cPk.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(encKey)); 

     byte[] bytes = bOut.toByteArray(); 

     OutputStream cOut = cPk.open(out, bytes.length); 

     cOut.write(bytes); 

     cOut.close(); 

     out.close(); 
    } 

Teraz Oto jak wywołać/run powyższego:

try { 
      decryptFile(new FileInputStream("encryptedFile.gpg"), new FileInputStream("PrivateKey.asc"), new FileInputStream("PublicKey.asc"), "yourKeyPassword".toCharArray()); 

      PGPPublicKey pubKey = readPublicKeyFromCol(new FileInputStream("PublicKey.asc")); 

      encryptFile(new FileOutputStream("encryptedFileOutput.gpg"), "fileToEncrypt.txt", pubKey); 




     } catch (PGPException e) { 
      fail("exception: " + e.getMessage(), e.getUnderlyingException()); 
     }