简体   繁体   中英

java pgp encrypt file with public key in asc file

My customer use PGP desktop for file encryption. They send me a public key in an.asc file and I have to encrypt a zip file by this public key with java. But I can't find any java code that use asc file. There are some potential lib, such as didisoft but they only have commercial version. An example of asc bellow.

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

You can use the crypto library 'Bouncy Castle' to encrypt a file using a PGP Public key in Ascii-format. The following code is taken from the examples section of Bouncy Castle that is located here: https://github.com/bcgit/bc-java/tree/master/pg/src/main/java/org/bouncycastle/openpgp/examples .

You do need the two files KeyBasedLargeFileProcessor.java and PGPExampleUtil.java plus the libraries itself; 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).

As the example is a command line application you need to pass the information like

-e -a plaintext.txt java_pgp_encrypt_publickey.asc

where -e = encryption, -a = ascii output, plaintext.txt is your file to get encrypted and java_pgp_encrypt_publickey.asc = the public key.

There are some other options but they depend on the third party requests.

Please take care about the notes in KeyBasedLargeFileProcessor.java - this is just a working example.

Usually there is not extra output but a new file in the current directory with the filename plaintext.txt.asc that looks like

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

Edit Aug. 12th 2020: I made a fresh download of PGP Desktop x64 version 10.1.1, generated a sample keypair and exported the public key ("-----BEGIN PGP PUBLIC KEY BLOCK-----..."). I used this key with the mentioned options and created a encrypted file ("-----BEGIN PGP MESSAGE-----..."). This file was used as input for the PGP Viewer and it was decrypted like expected, so something in your environment seems not to work as expected (or the wrong public key was in use or or or):

在此处输入图像描述

As links may go away here are the source codes as well.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM