您的位置:首页 > 编程语言 > Java开发

基于Java Bouncy Castle的PGP加密解密示例

2017-09-07 16:38 423 查看
PGP即Pretty Good Privacy,是一个基于RSA公钥&私钥及AES等非对称加密算法的加密软件系列,比较具有代表性加密解密客户端已被Symantec收购,详见www.pgp.com,在Symantec的网站上可以下载最新版客户端软件。

本文讲的是使用Java基于Bouncy Castle包的PGP加密解密示例,按照以下步骤即可轻松实现:

1. 客户端软件
由于Symantec的PGP客户端是收费软件,本文只需要使用其中的生成秘钥和加密文件的功能,用该软件有些浪费,所以我下载了Java 免费版的Portable PGP(http://sourceforge.net/projects/ppgp/)

2. 下载Bouncy Castle包
http://www.bouncycastle.org/latest_releases.html


bcprov-jdk15on-148.jar和bcpg-jdk15on-148.jar

Bouncy Castle支持大量的密码术算法,其中包括OpenPGP,引用很广泛,Pega就是使用Bouncy Castle对邮件和客户重要数据进行加密解密的。

它既可以安装成JDK扩展也可以放到特定java项目中使用。

3. 在Oracle官网下载UnlimitedJCEPolicy
http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
JDK默认Policy只能支持<=128位Key,GPG的密钥从1024-2048,所以必须扩展该Policy。具体安装方法参考文件中的ReadMe文件。

4. 编写代码
使用Portable PGP加密文件后生成Public Key和Private Key。把试用Public Key加密的文件"Encrypted File.txt"和Private Key "Key.asc"一同放到项目文件夹中。
使用以下代码即可解密文件。(拷贝以下代码可以直接执行,以下代码也是来自Bouncy Castle源代码包)

PGPExampleUtil.java

package com.zolly.bouncycastle;

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;

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

     * @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(pass, "BC");

    }

    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

     * @return

     * @throws IOException

     * @throws PGPException

     */

    static PGPPublicKey readPublicKey(InputStream input) throws IOException, PGPException

    {

        PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(

            PGPUtil.getDecoderStream(input));

        //

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

        //

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

    }

}

KeyBasedLargeFileProcessor.java

package com.zolly.bouncycastle;

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.PGPObjectFactory;
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.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.

 */
public class KeyBasedLargeFileProcessor

{

    public 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

     */

    public static void decryptFile(

        InputStream in,

        InputStream keyIn,

        char[]      passwd,

        String      defaultFileName)

        throws IOException, NoSuchProviderException

    {    

        in = PGPUtil.getDecoderStream(in);

        

        try

        {

            PGPObjectFactory        pgpF = new PGPObjectFactory(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));                                                                 

            

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

            

            PGPObjectFactory    plainFact = new PGPObjectFactory(clear);

            

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

    

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

            PGPObjectFactory    pgpFact = new PGPObjectFactory(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();

            }

        }

    }

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

    }

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

        

        decryptFile("Encypted File.txt.pgp", "Key.asc", "123456789".toCharArray(), "Encypted File.txt");

    }

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: