java pgp加密
maven pom
<dependencies> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpg-jdk15on</artifactId> <version>1.68</version> </dependency> <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on --> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.68</version> </dependency> </dependencies>
KeyBasedLargeFileProcessor
package com.zhianchen; 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.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. */ public class KeyBasedLargeFileProcessor { /** * * @param inputFileName 要解密的文件名 * @param keyFileName 私钥 * @param passwd 私钥解密key * @param defaultFileName 输出解密的文件 * @throws IOException * @throws NoSuchProviderException */ 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 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()); 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)); // PGPObjectFactory plainFact = new PGPObjectFactory(clear); PGPObjectFactory plainFact = new JcaPGPObjectFactory(clear); PGPCompressedData cData = (PGPCompressedData)plainFact.nextObject(); InputStream compressedStream = new BufferedInputStream(cData.getDataStream()); //PGPObjectFactory pgpFact = new PGPObjectFactory(compressedStream); PGPObjectFactory 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(); } } } /** * * @param outputFileName * @param inputFileName * @param encKeyFileName * @param armor 指示是否应该使用ASCII装甲格式 * @param withIntegrityCheck 检查完整性 * @throws IOException * @throws NoSuchProviderException * @throws PGPException */ 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(); } /** * * @param out * @param fileName * @param encKey * @param armor 指示是否应该使用ASCII装甲格式 * @param withIntegrityCheck 检查完整性 * @throws IOException * @throws NoSuchProviderException */ 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")); PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(new JcePGPDataEncryptorBuilder(PGPEncryptedData.AES_256).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()); encryptFile("Encypted File.txt.pgp", "Key.asc", "public.pem", true,true); decryptFile("Encypted File.txt.pgp", "private.pem", "123456789".toCharArray(), "Encypted File.txt"); } }
PGPExampleUtil
package com.zhianchen; 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 * @throws PGPException * @throws NoSuchProviderException */ public 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"); 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 * @return * @throws IOException * @throws PGPException */ static PGPPublicKey readPublicKey(InputStream input) throws IOException, PGPException { // PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection( // PGPUtil.getDecoderStream(input)); 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)); 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."); } }
PgpUtil
package com.zhianchen; import org.bouncycastle.bcpg.ArmoredOutputStream; import org.bouncycastle.bcpg.HashAlgorithmTags; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openpgp.*; import org.bouncycastle.openpgp.operator.PGPDigestCalculator; import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair; import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; import sun.misc.BASE64Encoder; import java.io.ByteArrayOutputStream; import java.io.FileOutputStream; import java.io.OutputStream; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.Security; import java.util.Date; import java.util.UUID; import static jdk.nashorn.internal.objects.NativeString.substring; public class PgpUtil { private static final String IDENTITY="PGPID"; private static final int KEY_WIDTH=2048; /** * 私有方法,用于生成指定位宽的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) ); } /** * 输出带pem的text * @param armor * @param identity * @param passPhrase * @param keyWidth * @param pubKeyFile * @param priKeyFile * @return * @throws Exception */ public static String[] getPGPSecretkey(boolean armor, String identity, String passPhrase, int keyWidth,String pubKeyFile, String priKeyFile) throws Exception { OutputStream priKeyOutputstream; OutputStream pubKeyOutputstream; try (ByteArrayOutputStream pubKeyOut = new ByteArrayOutputStream(); ByteArrayOutputStream priKeyOut = new ByteArrayOutputStream()) { if (armor) { // key format with armored priKeyOutputstream = new ArmoredOutputStream(priKeyOut); pubKeyOutputstream = new ArmoredOutputStream(pubKeyOut); } else { // key format without armored priKeyOutputstream = new FileOutputStream(priKeyFile); pubKeyOutputstream = new FileOutputStream(pubKeyFile); } Security.addProvider(new BouncyCastleProvider()); PGPSecretKey secretKey = PgpUtil.getSecretKey(identity, passPhrase, keyWidth); secretKey.encode(priKeyOutputstream); (priKeyOutputstream).close(); PGPPublicKey publicKey = secretKey.getPublicKey(); publicKey.encode(pubKeyOutputstream); (pubKeyOutputstream).close(); String[] keyPair = new String[2]; if (armor) { keyPair[0] = pubKeyOut.toString(); keyPair[1] = priKeyOut.toString(); } else { keyPair[0] = pubKeyFile; keyPair[1] = priKeyFile; } return keyPair; } } /** * 设置密码生成密钥对 * @param passPhrase * @return * @throws Exception */ public static String[] generatePePKeyPair(String passPhrase) throws Exception { Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); PGPSecretKey secretKey = PgpUtil.getSecretKey(IDENTITY, passPhrase, KEY_WIDTH); String privateKeyString = new BASE64Encoder().encode(secretKey.getEncoded()); PGPPublicKey publicKey = secretKey.getPublicKey(); byte[] encoded = publicKey.getEncoded(); String publicKeyString = new BASE64Encoder().encode(encoded); String[] keyPair = new String[2]; keyPair[0] = publicKeyString; keyPair[1] = privateKeyString; return keyPair; } /** * 根据密码生成带pem的密钥对,包含begin end * @param passPhrase * @return * @throws Exception */ public static String[] generatePePKeyBlockPair(String passPhrase) throws Exception { return getPGPSecretkey(true, IDENTITY, passPhrase, KEY_WIDTH, null, null); } /** * 生成带pem的密钥对,包含begin end * @param * @return * @throws Exception */ public static String[] generatePgPKeyBlockPairAndPhrase() throws Exception { String[] keyBlockPair = new String[3]; String passPhrase = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 8); String[] keyPair = getPGPSecretkey(true, IDENTITY, passPhrase, KEY_WIDTH, null, null); keyBlockPair[0] = keyPair[0]; keyBlockPair[1] = keyPair[1]; keyBlockPair[2] = passPhrase; return keyBlockPair; } /** * 生成带pem的密钥对,包含begin end * @param * @return * @throws Exception */ public static String[] generatePgPKeyBlockPairAndPhrase(String identity,String passPhrase) throws Exception { String[] keyBlockPair = new String[3]; String[] keyPair = getPGPSecretkey(true, identity, passPhrase, KEY_WIDTH, null, null); keyBlockPair[0] = keyPair[0]; keyBlockPair[1] = keyPair[1]; keyBlockPair[2] = passPhrase; return keyBlockPair; } @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); String[] stringArr1 = generatePePKeyPair(passPhrase_); String[] stringArr2 = generatePePKeyBlockPair(passPhrase_); String[] stringArr3 = generatePgPKeyBlockPairAndPhrase(); System.out.println("-----------privateKey--------"); System.out.println(stringArr3[1]); System.out.println("-----------publicKey--------"); System.out.println(stringArr3[0]); System.out.println("-----------passPhrase--------"); System.out.println(stringArr3[3]); } }