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

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");
    }
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
BouncyCastleJava 平台上的一个加解密库,支持多种加密算法,包括 PGP 加解密。以下是使用 BouncyCastle 实现 PGP 加密解密文件的示例代码: 1. 加载 BouncyCastle Provider: ``` Security.addProvider(new BouncyCastleProvider()); ``` 2. 生成 PGP 密钥对: ``` PGPKeyPairGenerator kpg = new JcaPGPKeyPairGenerator().setProvider("BC").setAlgorithm(AsymmetricAlgorithmTags.RSA_GENERAL).setKeySize(2048); PGPKeyPair kp = kpg.generate(); ``` 3. 导出公钥和私钥: ``` PGPPublicKeyRing publicKeyRing = new PGPPublicKeyRing(kp.getPublicKey().getEncoded(), new JcaKeyFingerprintCalculator()); PGPPublicKey publicKey = publicKeyRing.getPublicKey(); PGPPrivateKey privateKey = kp.getPrivateKey(); ``` 4. 加密文件: ``` // 创建加密器 PGPEncryptorBuilder builder = new JcePGPEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_256).setSecureRandom(new SecureRandom()); builder.setProvider("BC"); PGPEncryptor encryptor = builder.build(publicKey); // 创建输出流 File outputFile = new File("encrypted.pgp"); OutputStream outputStream = new FileOutputStream(outputFile); // 创建压缩器 PGPCompressedDataGenerator compressor = new PGPCompressedDataGenerator(CompressionAlgorithmTags.ZIP); OutputStream compressedOutputStream = compressor.open(outputStream); // 创建签名器 PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(PublicKeyAlgorithmTags.RSA_GENERAL, HashAlgorithmTags.SHA256).setProvider("BC")); signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, privateKey); signatureGenerator.generateOnePassVersion(false).encode(compressedOutputStream); // 创建字节流加密器 PGPLiteralDataGenerator literalDataGenerator = new PGPLiteralDataGenerator(); OutputStream literalOutputStream = literalDataGenerator.open(compressedOutputStream, PGPLiteralData.BINARY, "filename", new Date(), new byte[1024]); // 加密文件内容 File inputFile = new File("input.txt"); InputStream inputStream = new FileInputStream(inputFile); byte[] buffer = new byte[1024]; int length; while ((length = inputStream.read(buffer)) != -1) { literalOutputStream.write(buffer, 0, length); } inputStream.close(); // 关闭流 literalDataGenerator.close(); signatureGenerator.generate().encode(compressedOutputStream); compressor.close(); encryptor.close(); outputStream.close(); ``` 5. 解密文件: ``` // 创建解密器 PGPObjectFactory factory = new JcaPGPObjectFactory(new FileInputStream("encrypted.pgp")); PGPEncryptedDataList encryptedDataList = (PGPEncryptedDataList) factory.nextObject(); PGPPBEEncryptedData pbeEncryptedData = (PGPPBEEncryptedData) encryptedDataList.get(0); PGPPrivateKey privateKey = findPrivateKey("userid", "password".toCharArray()); InputStream decryptedInputStream = pbeEncryptedData.getDataStream(new JcePBEDataDecryptorFactoryBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("BC").build()).setProvider("BC").build(privateKey)); // 创建签名校验器 PGPObjectFactory plainFactory = new JcaPGPObjectFactory(decryptedInputStream); PGPOnePassSignatureList signatureList = (PGPOnePassSignatureList) plainFactory.nextObject(); PGPOnePassSignature signature = signatureList.get(0); PGPPublicKey publicKey = findPublicKey(signature.getKeyID()); signature.init(new JcaPGPContentVerifierBuilderProvider().setProvider("BC"), publicKey); PGPLiteralData literalData = (PGPLiteralData) plainFactory.nextObject(); InputStream literalInputStream = literalData.getInputStream(); // 校验签名 byte[] buffer = new byte[1024]; int length; while ((length = literalInputStream.read(buffer)) != -1) { signature.update(buffer, 0, length); } if (signature.verify(((PGPSignatureList) plainFactory.nextObject()).get(0))) { System.out.println("Signature verified"); } else { System.out.println("Signature not verified"); } // 读取文件内容 while ((length = literalInputStream.read(buffer)) != -1) { // 处理文件内容 } literalInputStream.close(); decryptedInputStream.close(); ``` 其中,`findPrivateKey` 和 `findPublicKey` 方法根据指定的用户 ID 查找对应的私钥和公钥。在实际使用时,需要将用户 ID 和密钥信息存储在合适的位置,例如文件或数据库中,然后在程序中进行读取。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值