java 实现PGP生成公私钥对生成,以及加解密文件

介绍

最近和联通的数据生成系统对接需要使用PGP工具,网上查了资料,调了一整天终于出来了,下面介绍下使用方法以及碰到的一些的小坑

使用方法

依赖jar包

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpg-jdk15on</artifactId>
    <version>1.64</version>
</dependency>

bcprov-jdk15on.jar 常用的加解密jar包,相信大家都很熟悉了,我们通过它来实现PGP加解密及生成公私钥对

生成公私钥对的方法

public class PgpUtil {

	
	/**
	 * 私有方法,用于生成指定位宽的PGP RSA密钥对
	 *
	 * @param rsaWidth_ RSA密钥位宽
	 * @return 未经私钥加密的PGP密钥对
	 * @throws Exception IO错误,数值错误等
	 */
	private static PGPKeyPair generateKeyPair(int rsaWidth_) throws Exception {
	    KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "BC");//获取密钥对生成器实例
	    kpg.initialize(rsaWidth_);//设定RSA位宽
	    KeyPair kp = kpg.generateKeyPair();//生成RSA密钥对
	    return new JcaPGPKeyPair(PGPPublicKey.RSA_GENERAL, kp, new Date());//返回根据日期,密钥对生成的PGP密钥对
	}
	 
	/**
	 * 获取PGP密钥<br>
	 * 密钥是将密钥对的私钥部分用对称的加密方法CAST-128算法加密,再加上公钥部分
	 *
	 * @param identity_   密钥ID也就是key值,可以用来标记密钥属于谁
	 * @param passPhrase_ 密钥的密码,用来解出私钥
	 * @param rsaWidth_   RSA位宽
	 * @return PGP密钥
	 * @throws Exception IO错误和数值错误等
	 */
	public static PGPSecretKey getSecretKey(String identity_, String passPhrase_, int rsaWidth_) throws Exception {
	    char[] passPhrase = passPhrase_.toCharArray(); //将passPharse转换成字符数组
	    PGPKeyPair keyPair = PgpUtil.generateKeyPair(rsaWidth_); //生成RSA密钥对
	    PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1); //使用SHA1作为证书的散列算法
	    /**
	     * 用证书等级生成的认证,将公私钥对和PGP ID密码绑定构造PGP密钥(SecretKey)
	     *
	     * @param certificationLevel PGP密钥的证书等级
	     * @param keyPair 需要绑定的公私钥对
	     * @param id 需要绑定的ID
	     * @param checksumCalculator 散列值计算器,用于计算私钥密码散列
	     * @param hashedPcks the hashed packets to be added to the certification.(先不管)
	     * @param unhashedPcks the unhashed packets to be added to the certification.(也先不管)
	     * @param certificationSignerBuilder PGP证书的生成器
	     * @param keyEncryptor 如果需要加密私钥,需要在这里传入私钥加密器
	     * @throws PGPException 一些PGP错误
	     */
	    return new PGPSecretKey(
	            PGPSignature.DEFAULT_CERTIFICATION,
	            keyPair,
	            identity_,
	            sha1Calc,
	            null,
	            null,
	            new JcaPGPContentSignerBuilder(keyPair.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1),
	            //密钥的加密方式
	            new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.CAST5, sha1Calc).setProvider("BC").build(passPhrase)
	    );
	}
	
	@SuppressWarnings("restriction")
	public static void main(String[] args) throws Exception {
		Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
		String passPhrase_ = "123456789";
	    char[] passPhrase = passPhrase_.toCharArray(); //将passPharse转换成字符数组

		PGPSecretKey secretKey = PgpUtil.getSecretKey("wathdata", passPhrase_, 2048);

		// 这里打印私钥-------------重要
		String privateKeyString = new BASE64Encoder().encode(secretKey.getEncoded());  
		System.out.println(privateKeyString);
	
	
		PGPPublicKey publicKey = secretKey.getPublicKey();
		//FileOutputStream fileOutputStream = new FileOutputStream("c://1.txt");
		byte[] encoded = publicKey.getEncoded();
		// 这里打印公钥----------------重要
		String publicKeyString = new BASE64Encoder().encode(encoded);  
		System.out.println(publicKeyString);

	}
	

}

也可以使用 gpg4win 软件生成的密钥来获取公钥私钥
下载地址: gpg4win
生成后密钥文件:
密钥文件

文件加解密

import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.bcpg.CompressionAlgorithmTags;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.*;
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;

import java.io.*;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Base64;
import java.util.Iterator;

public class KeyBasedFileProcessorKey {

    /**
     * @param inputFileName   要解密的文件名
     * @param key             私钥
     * @param passwd          私钥解密key
     * @param defaultFileName 输出解密的文件
     * @throws IOException
     * @throws NoSuchProviderException
     */
    public static void decryptFile(String inputFileName, String key, char[] passwd, String defaultFileName) throws IOException, NoSuchProviderException {

        InputStream in = new BufferedInputStream(new FileInputStream(inputFileName));

        byte[] decode = Base64.getDecoder().decode(key);
        decryptFile(in, decode, passwd, defaultFileName);

        in.close();

    }

    /**
     * decrypt the passed in message stream
     */

    private static void decryptFile(InputStream in, byte[] 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(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);
            Object message = plainFact.nextObject();

            if (message instanceof PGPCompressedData) {
                PGPCompressedData cData = (PGPCompressedData) message;
                JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(cData.getDataStream());
                message = pgpFact.nextObject();
            }

            if (message instanceof PGPLiteralData) {
                PGPLiteralData ld = (PGPLiteralData) message;
                String outFileName = ld.getFileName();
                if (outFileName.length() == 0) {
                    outFileName = defaultFileName;
                } else {

                    /**
                     * modify 20160520
                     * set fileName
                     * 不同的系统可能源文件的包含的路径信息不同。
                     */

                    String separator = "";
                    if (outFileName.contains("/")) {
                        separator = "/";
                    } else if (outFileName.contains("\\")) {
                        separator = "\\";
                    }
                    String fileName = outFileName.substring(outFileName.lastIndexOf(File.separator) + 1);

                    String defseparator = "";
                    if (defaultFileName.contains("/")) {
                        defseparator = "/";
                    } else if (defaultFileName.contains("\\")) {
                        defseparator = "\\";
                    }

                    defaultFileName = defaultFileName.substring(0, defaultFileName.lastIndexOf(defseparator));
                    outFileName = defaultFileName + File.separator + fileName;

                }

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

    /**
     * @param outputFileName     输出的加密文件名 2.pgp
     * @param inputFileName      输入的要加密的文件
     * @param encryKey           公钥
     * @param armor              true
     * @param withIntegrityCheck true
     * @throws IOException
     * @throws NoSuchProviderException
     * @throws PGPException
     */
    public static void encryptFile(String outputFileName, String inputFileName, String encryKey, boolean armor, boolean withIntegrityCheck) throws IOException, NoSuchProviderException, PGPException {

        OutputStream out = new BufferedOutputStream(new FileOutputStream(outputFileName));
        Base64.Decoder decoder = Base64.getDecoder();
        byte[] decode = decoder.decode(encryKey);
        PGPPublicKey encKey = PGPExampleUtil.readPublicKey(new ByteArrayInputStream(decode));

        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 {
            byte[] bytes = PGPExampleUtil.compressFile(fileName, CompressionAlgorithmTags.ZIP);
            PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(
                    new JcePGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setWithIntegrityPacket(withIntegrityCheck)
                            .setSecureRandom(new SecureRandom()).setProvider("BC"));

            encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encKey).setProvider("BC"));
            OutputStream cOut = encGen.open(out, bytes.length);
            cOut.write(bytes);
            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 {

		//public key
        String keyString = "public key";
        //private key
        String privateKeyString = "private key";

        Security.addProvider(new BouncyCastleProvider());
        encryptFile("C:\\pgp\\testFiles\\New folder\\test1.txt.pgp", "C:\\pgp\\testFiles\\New folder\\test1.txt", keyString, true, true); // 加密文件
        decryptFile("C:\\pgp\\testFiles\\New folder\\test1.txt.pgp", privateKeyString, "password".toCharArray(), "C:\\pgp\\testFiles\\New folder\\test3.txt");// 解密文件

    }

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

文件加密解密可以用代码和gpg4win软件互相验证

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
PGP(Pretty Good Privacy)是一种用于加密和签名电子邮件、文档和文件的加密协议。它使用对称加密和非对称加密结合的方式,能够保证通信的安全性。 Java中可以使用Bouncy Castle库来实现PGP加解密,具体步骤如下: 1. 首先,需要导入Bouncy Castle库: ```java import org.bouncycastle.openpgp.*; import org.bouncycastle.openpgp.operator.jcajce.*; ``` 2. 加载钥和私钥 ```java PGPPublicKeyRing publicKeyRing = new PGPPublicKeyRing(pubKeyRingCollection); PGPPublicKey publicKey = publicKeyRing.getPublicKey(publicKeyId); PGPSecretKeyRing secretKeyRing = new PGPSecretKeyRing(secretKeyRingCollection); PGPSecretKey secretKey = secretKeyRing.getSecretKey(secretKeyId); ``` 3. 加密数据 ```java byte[] data = "hello, world!".getBytes("UTF-8"); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); PGPLiteralDataGenerator literalDataGenerator = new PGPLiteralDataGenerator(); OutputStream encryptedOutputStream = literalDataGenerator.open(outputStream, PGPLiteralData.BINARY, "", data.length, new Date()); encryptedOutputStream.write(data); encryptedOutputStream.close(); PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(new JcePGPDataEncryptorBuilder(PGPEncryptedData.AES_256).setWithIntegrityPacket(true).setSecureRandom(new SecureRandom()).setProvider("BC")); encryptedDataGenerator.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(publicKey).setProvider("BC")); byte[] encryptedData = outputStream.toByteArray(); ``` 4. 解密数据 ```java ByteArrayInputStream inputStream = new ByteArrayInputStream(encryptedData); PGPObjectFactory objectFactory = new PGPObjectFactory(PGPUtil.getDecoderStream(inputStream), new JcaKeyFingerprintCalculator()); PGPCompressedData compressedData = (PGPCompressedData) objectFactory.nextObject(); objectFactory = new PGPObjectFactory(compressedData.getDataStream(), new JcaKeyFingerprintCalculator()); PGPLiteralData literalData = (PGPLiteralData) objectFactory.nextObject(); InputStream literalDataStream = literalData.getInputStream(); byte[] decryptedData = new byte[literalData.getLength()]; IOUtils.readFully(literalDataStream, decryptedData); literalDataStream.close(); ``` 以上就是使用Java实现PGP加解密的基本步骤。需要注意的是,Bouncy Castle库的使用需要引入相应的jar包,并且还需要导入Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files,否则会出现加密强度不足的问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值