2013-02-21 77 views
10

讓我開始說我對這一切都非常陌生。我想要做的是從Java內部使用gpg來解密加密文件。讓GPG解密在Java中工作(Bouncy Castle)

我已經成功地完成:

  • 有一個同事使用我的公鑰和自己的私鑰加密文件,併成功解密它。

  • 走到另一條路

  • 有另一個同事嘗試解密,這不是他一個文件:失敗(如預期)這樣產生

我的鑰匙......

(GPG --version告訴我,我使用的是1.4.5,我用充氣城堡1.47)

GPG --gen-萊伊

選擇選項「DSA和Elgamal(默認)」

填寫其他字段並生成密鑰。

該文件已使用我的公鑰和另一個密鑰加密。我想解密它。我已經編寫了下面的Java代碼來完成這個任務。我使用了幾個不推薦使用的方法,但我無法弄清楚如何正確實現使用非棄用版本所需的工廠方法,所以如果有人對我應該使用的那些實現有一個想法,那將是一個不錯的獎金。

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"); 

所以,當我運行此代碼,我得知我的算法和格式是我的祕密密鑰如下:

算法:DSA 格式:PKCS#8

然後它打破上最後一行:

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) 

產生的原因:java.security.InvalidKeyException:未知的密鑰類型傳遞到的ElGamal 在org.bouncyc astle.jcajce.provider.asymmetric.elgamal.CipherSpi.engineInit(Unknown Source) at org.bouncycastle.jcajce.provider.asymmetric.elgamal.CipherSpi.engineInit(Unknown Source) at javax.crypto.Cipher.init(DashoA13 * ..) 在javax.crypto.Cipher.init(DashoA13 * ..) ... 8個

我接受了很多建議在這裏,從「不使用GPG,用x代替「到」不要使用充氣城堡,用x來代替「之間的任何事物。謝謝!

回答

2

我決定去一個非常不同的方法,這是放棄使用有彈性的完全是城堡,只需使用運行時進程即可。對我來說,這個解決方案是工作和完全消除周圍的充氣城堡的複雜性:

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

這樣做,你需要記住耗盡你的輸入流作爲你的進程execing或你的程序可能會掛起取決於有多少之後,你正在輸出。在這個主題中看到我的回答(也是Cameron Skinner和Matthew Wilson的回答,讓我有更多的上下文):Calling GnuPG in Java via a Runtime Process to encrypt and decrypt files - Decrypt always hangs

+1

+1 Ewwwwwwwwwwww;) – 2013-02-21 19:55:20

+9

-1原因很明顯。此外,在通話過程中,任何查看活動進程列表的人都可以看到您的密碼,也可能會在系統日誌中顯示。 – user359996 2013-05-21 18:00:54

1

第一個Google結果是this。看起來您正在嘗試解密ElGamal數據,但您沒有傳入ElGamal密鑰。

有兩個簡單的可能性:

  • 你的鑰匙圈收集有多個鑰匙扣。
  • 您的鑰匙圈有子項。

你已經選擇了ElGamal加密的DSA,所以我懷疑至少後者:子密鑰由主密鑰簽名; ElGamal不是一種簽名算法(我不知道DSA和ElGamal是否可以使用相同的密鑰,但通常認爲使用不同的密鑰用於不同的目的是個好主意)。

我想你想這樣的事情(也secretKeyRing也許應該改名爲secretKeyRingCollection):

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

感謝您的迴應。我同意這個命名。我的鍵肯定有一個子鍵(至少當我使用gpg --list-keys來查看它時)。但我可以在命令行解密使用它。我在這裏留下了什麼? – Craig 2013-02-21 03:17:41

+0

ElGamal鍵是子鍵嗎? – 2013-02-21 04:48:59

+0

嗨tc。我決定在java中採用不同的gpg解密方法。我非常欣賞這種迴應,但對我來說,有一個更簡單的解決方案,我將在下面的答案中詳細說明。 – Craig 2013-02-21 14:10:27

7

如果有人想知道如何使用彈性來加密和解密gpg文件城堡的OpenPGP庫,請檢查下面的Java代碼:

以下是4種方法,你將需要:

下面的方法將讀取並從.ASC文件導入您的密鑰:

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

貝爾流方法讀取和.ASC文件中導入你的公鑰:

@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; 
    } 

以下2種方法來解密和加密文件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(); 
    } 

現在這裏是如何調用/運行上面:

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()); 
     } 
相關問題