簡體   English   中英

java pgp 用 asc 文件中的公鑰加密文件

[英]java pgp encrypt file with public key in asc file

我的客戶使用 PGP 桌面進行文件加密。 他們向我發送了一個 .asc 文件中的公鑰,我必須用這個公鑰和 java 加密 zip 文件。 但我找不到任何使用 asc 文件的 java 代碼。 有一些潛在的庫,例如 didisoft,但它們只有商業版本。 下面是 asc 的一個例子。

-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: PGP Desktop 10.1.1 (Build 10) - not licensed for commercial use: www.pgp.com

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
=bQJS
-----END PGP PUBLIC KEY BLOCK-----

您可以使用加密庫“Bouncy Castle”使用 Ascii 格式的 PGP 公鑰加密文件。 以下代碼來自位於此處的 Bouncy Castle 的示例部分: https://github.com/bcgit/bc-java/tree/master/pg/src/main/java/org/bouncycastle/openpgp/examples .

您確實需要兩個文件 KeyBasedLargeFileProcessor.java 和 PGPExampleUtil.java 以及庫本身; get the latest versions here: https://www.bouncycastle.org/latest_releases.html (you need the bcprov-xxx.jar and bcpg-xxx.jar to run the example).

由於示例是一個命令行應用程序,您需要傳遞如下信息

-e -a plaintext.txt java_pgp_encrypt_publickey.asc

其中 -e = 加密,-a = ascii output,plaintext.txt 是您要加密的文件,java_pgp_encrypt_publickey.asc = 公鑰。

還有一些其他選項,但它們取決於第三方請求。

請注意 KeyBasedLargeFileProcessor.java 中的注釋 - 這只是一個工作示例。

通常沒有額外的 output 而是當前目錄中的一個新文件,文件名為 plaintext.txt.asc 看起來像

-----BEGIN PGP MESSAGE-----
Version: BCPG v1.66

hQEMAyr8BYmnLERrAQf/SaG7yIORewag0fziemyEmWq+sGJT3TiLIoVCEo+PjDfY
XyuXybIr/q5Q7tE3WcubkXzVIuShB2x2r8zaHP3rhtzDfuRS13S5QBM1LZ9KIcvg
+//OoeS1kfKfJnYfAQR1VCKWBkOQtSCIyMWGmqkrV2xEC8xzAo2cwXCBS2F7LYRE
vnmJGnr4ANFdbSlzRffBPJCcggk9RqDXXJjU31gCqFT+lpgc48Hf6OfRff7x5I2b
5++PH1UPKFIZhalnFE2UQ9DVbzJd2FaciUKhcM9nQSGKoNKy3o1wevrtive8VIuM
JjgV0ql+3MGCVVYL0tBnDdjdbmHV5pcZX9aI147esclPItwZQHTHTtaxTUKTJZeQ
4YgMas+o0faWLUilaeNvNa8PqxLy9gPGzMxUj2/P1narGs4bbivUooLJO73NKV4B
u3on8l/Es4vVLNoZpJv0kw==
=IZ8I
-----END PGP MESSAGE-----

2020 年 8 月 12 日編輯:我重新下載了 PGP Desktop x64 版本 10.1.1,生成了一個示例密鑰對並導出了公鑰(“-----BEGIN PGP PUBLIC KEY BLOCK-----...” )。 我將此密鑰與上述選項一起使用並創建了一個加密文件(“-----BEGIN PGP MESSAGE-----...”)。 該文件被用作 PGP 查看器的輸入,並按預期進行了解密,因此您的環境中的某些內容似乎沒有按預期工作(或使用了錯誤的公鑰或或或):

在此處輸入圖像描述

由於鏈接可能 go 這里是源代碼以及。

class KeyBasedLargeFileProcessor.java

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Iterator;

import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPCompressedData;
import org.bouncycastle.openpgp.PGPCompressedDataGenerator;
import org.bouncycastle.openpgp.PGPEncryptedData;
import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
import org.bouncycastle.openpgp.PGPEncryptedDataList;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPLiteralData;
import org.bouncycastle.openpgp.PGPOnePassSignatureList;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
import org.bouncycastle.util.io.Streams;

/**
 * A simple utility class that encrypts/decrypts public key based
 * encryption large files.
 * <p>
 * To encrypt a file: KeyBasedLargeFileProcessor -e [-a|-ai] fileName publicKeyFile.<br>
 * If -a is specified the output file will be "ascii-armored".
 * If -i is specified the output file will be have integrity checking added.
 * <p>
 * To decrypt: KeyBasedLargeFileProcessor -d fileName secretKeyFile passPhrase.
 * <p>
 * Note 1: this example will silently overwrite files, nor does it pay any attention to
 * the specification of "_CONSOLE" in the filename. It also expects that a single pass phrase
 * will have been used.
 * <p>
 * Note 2: this example generates partial packets to encode the file, the output it generates
 * will not be readable by older PGP products or products that don't support partial packet
 * encoding.
 * <p>
 * Note 3: if an empty file name has been specified in the literal data object contained in the
 * encrypted packet a file with the name filename.out will be generated in the current working directory.
 */
public class KeyBasedLargeFileProcessor
/*
   file taken from https://github.com/bcgit/bc-java/tree/master/pg/src/main/java/org/bouncycastle/openpgp/examples
   get bouncy castle here: https://www.bouncycastle.org/latest_releases.html
   i used the bcprov-jdk15on-166.jar and bcpg-jdk15on-166.jar at the time of writing
*/
{
    private static void decryptFile(
            String inputFileName,
            String keyFileName,
            char[] passwd,
            String defaultFileName)
            throws IOException, NoSuchProviderException
    {
        InputStream in = new BufferedInputStream(new FileInputStream(inputFileName));
        InputStream keyIn = new BufferedInputStream(new FileInputStream(keyFileName));
        decryptFile(in, keyIn, passwd, defaultFileName);
        keyIn.close();
        in.close();
    }

    /**
     * decrypt the passed in message stream
     */
    private static void decryptFile(
            InputStream in,
            InputStream keyIn,
            char[]      passwd,
            String      defaultFileName)
            throws IOException, NoSuchProviderException
    {
        in = PGPUtil.getDecoderStream(in);

        try
        {
            JcaPGPObjectFactory        pgpF = new JcaPGPObjectFactory(in);
            PGPEncryptedDataList    enc;

            Object                  o = pgpF.nextObject();
            //
            // the first object might be a PGP marker packet.
            //
            if (o instanceof PGPEncryptedDataList)
            {
                enc = (PGPEncryptedDataList)o;
            }
            else
            {
                enc = (PGPEncryptedDataList)pgpF.nextObject();
            }

            //
            // find the secret key
            //
            Iterator                    it = enc.getEncryptedDataObjects();
            PGPPrivateKey               sKey = null;
            PGPPublicKeyEncryptedData   pbe = null;
            PGPSecretKeyRingCollection  pgpSec = new PGPSecretKeyRingCollection(
                    PGPUtil.getDecoderStream(keyIn), new JcaKeyFingerprintCalculator());

            while (sKey == null && it.hasNext())
            {
                pbe = (PGPPublicKeyEncryptedData)it.next();

                sKey = PGPExampleUtil.findSecretKey(pgpSec, pbe.getKeyID(), passwd);
            }

            if (sKey == null)
            {
                throw new IllegalArgumentException("secret key for message not found.");
            }

            InputStream         clear = pbe.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC").build(sKey));

            JcaPGPObjectFactory    plainFact = new JcaPGPObjectFactory(clear);

            PGPCompressedData   cData = (PGPCompressedData)plainFact.nextObject();

            InputStream         compressedStream = new BufferedInputStream(cData.getDataStream());
            JcaPGPObjectFactory    pgpFact = new JcaPGPObjectFactory(compressedStream);

            Object              message = pgpFact.nextObject();

            if (message instanceof PGPLiteralData)
            {
                PGPLiteralData ld = (PGPLiteralData)message;

                String outFileName = ld.getFileName();
                if (outFileName.length() == 0)
                {
                    outFileName = defaultFileName;
                }

                InputStream unc = ld.getInputStream();
                OutputStream fOut =  new BufferedOutputStream(new FileOutputStream(outFileName));

                Streams.pipeAll(unc, fOut);

                fOut.close();
            }
            else if (message instanceof PGPOnePassSignatureList)
            {
                throw new PGPException("encrypted message contains a signed message - not literal data.");
            }
            else
            {
                throw new PGPException("message is not a simple encrypted file - type unknown.");
            }

            if (pbe.isIntegrityProtected())
            {
                if (!pbe.verify())
                {
                    System.err.println("message failed integrity check");
                }
                else
                {
                    System.err.println("message integrity check passed");
                }
            }
            else
            {
                System.err.println("no message integrity check");
            }
        }
        catch (PGPException e)
        {
            System.err.println(e);
            if (e.getUnderlyingException() != null)
            {
                e.getUnderlyingException().printStackTrace();
            }
        }
    }

    private static void encryptFile(
            String          outputFileName,
            String          inputFileName,
            String          encKeyFileName,
            boolean         armor,
            boolean         withIntegrityCheck)
            throws IOException, NoSuchProviderException, PGPException
    {
        OutputStream out = new BufferedOutputStream(new FileOutputStream(outputFileName));
        PGPPublicKey encKey = PGPExampleUtil.readPublicKey(encKeyFileName);
        encryptFile(out, inputFileName, encKey, armor, withIntegrityCheck);
        out.close();
    }

    private static void encryptFile(
            OutputStream    out,
            String          fileName,
            PGPPublicKey    encKey,
            boolean         armor,
            boolean         withIntegrityCheck)
            throws IOException, NoSuchProviderException
    {
        if (armor)
        {
            out = new ArmoredOutputStream(out);
        }

        try
        {
            PGPEncryptedDataGenerator   cPk = new PGPEncryptedDataGenerator(new JcePGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setWithIntegrityPacket(withIntegrityCheck).setSecureRandom(new SecureRandom()).setProvider("BC"));

            cPk.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encKey).setProvider("BC"));

            OutputStream                cOut = cPk.open(out, new byte[1 << 16]);

            PGPCompressedDataGenerator  comData = new PGPCompressedDataGenerator(
                    PGPCompressedData.ZIP);

            PGPUtil.writeFileToLiteralData(comData.open(cOut), PGPLiteralData.BINARY, new File(fileName), new byte[1 << 16]);

            comData.close();

            cOut.close();

            if (armor)
            {
                out.close();
            }
        }
        catch (PGPException e)
        {
            System.err.println(e);
            if (e.getUnderlyingException() != null)
            {
                e.getUnderlyingException().printStackTrace();
            }
        }
    }

    public static void main(
            String[] args)
            throws Exception
    {
        Security.addProvider(new BouncyCastleProvider());

        if (args.length == 0)
        {
            System.err.println("usage: KeyBasedLargeFileProcessor -e|-d [-a|ai] file [secretKeyFile passPhrase|pubKeyFile]");
            return;
        }

        if (args[0].equals("-e"))
        {
            if (args[1].equals("-a") || args[1].equals("-ai") || args[1].equals("-ia"))
            {
                encryptFile(args[2] + ".asc", args[2], args[3], true, (args[1].indexOf('i') > 0));
            }
            else if (args[1].equals("-i"))
            {
                encryptFile(args[2] + ".bpg", args[2], args[3], false, true);
            }
            else
            {
                encryptFile(args[1] + ".bpg", args[1], args[2], false, false);
            }
        }
        else if (args[0].equals("-d"))
        {
            decryptFile(args[1], args[2], args[3].toCharArray(), new File(args[1]).getName() + ".out");
        }
        else
        {
            System.err.println("usage: KeyBasedLargeFileProcessor -d|-e [-a|ai] file [secretKeyFile passPhrase|pubKeyFile]");
        }
    }
}

class PGPExampleUtil.java

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.NoSuchProviderException;
import java.util.Iterator;

import org.bouncycastle.openpgp.PGPCompressedDataGenerator;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPLiteralData;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;

class PGPExampleUtil
{
    static byte[] compressFile(String fileName, int algorithm) throws IOException
    {
        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
        PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(algorithm);
        PGPUtil.writeFileToLiteralData(comData.open(bOut), PGPLiteralData.BINARY,
                new File(fileName));
        comData.close();
        return bOut.toByteArray();
    }

    /**
     * Search a secret key ring collection for a secret key corresponding to keyID if it
     * exists.
     *
     * @param pgpSec a secret key ring collection.
     * @param keyID keyID we want.
     * @param pass passphrase to decrypt secret key with.
     * @return the private key.
     * @throws PGPException
     * @throws NoSuchProviderException
     */
    static PGPPrivateKey findSecretKey(PGPSecretKeyRingCollection pgpSec, long keyID, char[] pass)
            throws PGPException, NoSuchProviderException
    {
        PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);

        if (pgpSecKey == null)
        {
            return null;
        }

        return pgpSecKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("BC").build(pass));
    }

    static PGPPublicKey readPublicKey(String fileName) throws IOException, PGPException
    {
        InputStream keyIn = new BufferedInputStream(new FileInputStream(fileName));
        PGPPublicKey pubKey = readPublicKey(keyIn);
        keyIn.close();
        return pubKey;
    }

    /**
     * A simple routine that opens a key ring file and loads the first available key
     * suitable for encryption.
     *
     * @param input data stream containing the public key data
     * @return the first public key found.
     * @throws IOException
     * @throws PGPException
     */
    static PGPPublicKey readPublicKey(InputStream input) throws IOException, PGPException
    {
        PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(
                PGPUtil.getDecoderStream(input), new JcaKeyFingerprintCalculator());

        //
        // we just loop through the collection till we find a key suitable for encryption, in the real
        // world you would probably want to be a bit smarter about this.
        //

        Iterator keyRingIter = pgpPub.getKeyRings();
        while (keyRingIter.hasNext())
        {
            PGPPublicKeyRing keyRing = (PGPPublicKeyRing)keyRingIter.next();

            Iterator keyIter = keyRing.getPublicKeys();
            while (keyIter.hasNext())
            {
                PGPPublicKey key = (PGPPublicKey)keyIter.next();

                if (key.isEncryptionKey())
                {
                    return key;
                }
            }
        }

        throw new IllegalArgumentException("Can't find encryption key in key ring.");
    }

    static PGPSecretKey readSecretKey(String fileName) throws IOException, PGPException
    {
        InputStream keyIn = new BufferedInputStream(new FileInputStream(fileName));
        PGPSecretKey secKey = readSecretKey(keyIn);
        keyIn.close();
        return secKey;
    }

    /**
     * A simple routine that opens a key ring file and loads the first available key
     * suitable for signature generation.
     *
     * @param input stream to read the secret key ring collection from.
     * @return a secret key.
     * @throws IOException on a problem with using the input stream.
     * @throws PGPException if there is an issue parsing the input stream.
     */
    static PGPSecretKey readSecretKey(InputStream input) throws IOException, PGPException
    {
        PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(
                PGPUtil.getDecoderStream(input), new JcaKeyFingerprintCalculator());

        //
        // we just loop through the collection till we find a key suitable for encryption, in the real
        // world you would probably want to be a bit smarter about this.
        //

        Iterator keyRingIter = pgpSec.getKeyRings();
        while (keyRingIter.hasNext())
        {
            PGPSecretKeyRing keyRing = (PGPSecretKeyRing)keyRingIter.next();

            Iterator keyIter = keyRing.getSecretKeys();
            while (keyIter.hasNext())
            {
                PGPSecretKey key = (PGPSecretKey)keyIter.next();

                if (key.isSigningKey())
                {
                    return key;
                }
            }
        }

        throw new IllegalArgumentException("Can't find signing key in key ring.");
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM