web-dev-qa-db-ja.com

GPG復号化を機能させるJava(弾む城)

私はこれらすべてに非常に新しいと言うことから始めましょう。私がやろうとしているのは、暗号化されたファイルを復号化するために、Java内からgpgを使用することです。

私が成功したこと:

  • 同僚に私の公開鍵と彼の秘密鍵を使用してファイルを暗号化し、正常に復号化してもらいました。

  • 逆に行きました

  • 別の同僚が自分用ではないファイルを復号化しようとした場合:失敗(予想どおり)

私の鍵はこのように生成されました...

(gpg --versionは、1.4.5を使用していて、Bouncy Castle 1.47を使用していることを示しています)

gpg --gen-ley

オプション「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:不明なキータイプがorg.bouncycastle.jcajce.provider.asymmetric.elgamal.CipherSpi.engineInit(不明なソース)のorg.bouncycastle.jcajce.provider.asymmetric.elgamal.CipherSpiでElGamalに渡されました。 engineInit(Unknown Source)at javax.crypto.Cipher.init(DashoA13 * ..)at javax.crypto.Cipher.init(DashoA13 * ..)... 8詳細

ここでは、「gpgを使用せず、代わりにxを使用する」から、「弾力がある城を使用せず、代わりにxを使用する」など、さまざまな提案を受け付けています。ありがとう!

13
Craig

私は、弾力がある城の使用を完全に放棄し、代わりにランタイムプロセスを使用するという、はるかに異なるアプローチを採用することにしました。私にとって、このソリューションは機能しており、弾力がある城を取り巻く複雑さを完全に取り除きます。

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

その後、プロセスの実行中に入力ストリームをドレインすることを忘れないでください。そうしないと、出力量によってはプログラムがハングする可能性があります。もう少しコンテキストについては、このスレッドの私の回答(および適切なパスに私を導いたCameronSkinnerとMatthewWilsonの回答)を参照してください: ランタイムを介してJavaでGnuPGを呼び出す)ファイルを暗号化および復号化するプロセス-復号化は常にハングします

2
Craig

弾力のある城openPGPライブラリを使用してgpgファイルを暗号化および復号化する方法を知りたい場合は、以下を確認してください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;
    }

Gpgファイルを復号化および暗号化する以下の2つの方法:

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

別の解決策を探している人は、 https://stackoverflow.com/a/42176529/7550201 を参照してください。

final InputStream plaintextStream = BouncyGPG
           .decryptAndVerifyStream()
           .withConfig(keyringConfig)
           .andRequireSignatureFromAllKeys("[email protected]")
           .fromEncryptedInputStream(cipherTextStream)

短編小説:Bouncycastleはプログラミングが多いです カーゴカルトプログラミング そして私はそれを変更するためにライブラリを書きました。

2
Jens

最初の Google 結果は this です。 ElGamalデータを復号化しようとしているようですが、ElGamalキーを渡していないようです。

2つの簡単な可能性があります:

  • キーリングコレクションには複数のキーリングがあります。
  • キーリングにはサブキーがあります。

ElGamal暗号化を使用したDSAを選択したので、少なくとも後者は疑わしいです。サブキーはマスターキーによって署名されています。 ElGamalは署名アルゴリズムではありません(DSAとElGamalが同じキーを使用できるかどうかはわかりませんが、一般に、異なる目的で異なるキーを使用することをお勧めします)。

私はあなたがこのようなものが欲しいと思います(また、secretKeyRingはおそらくsecretKeyRingCollectionに名前を変更する必要があります):

PGPSecretKey secretKey = secretKeyRing.getSecretKey(publicKeyEncryptedData.getKeyID());
1
tc.

エラーメッセージは完全に正確ではないため、難しいものです。不正なキーサイズまたはデフォルトパラメータに加えて、例外は、暗号化許可チェックが失敗したために失敗した可能性があることを示しています。これは、JCE権限が適切に設定されていないことを意味します。 JCE Unlimited Strength Policy をインストールする必要があります。

Jvmでシステムプロパティを設定すると、デバッグメッセージを表示できます。

Java -Djava.security.debug=access ....
0
chubbsondubs