银行对接保险公司要对文件进行gpg加密,那保险公司要进行解密了。
原来想的方案是用java代码编写cmd命令然后执行bat文件,生成指定的文件夹下。这样的话有几个弊端:第一次运行bat文件的时候总是会提示要输入密码,发布到服务器上是不可控的。另一个是服务器是windows系统的话还要安装gpg的软件。
后来发现java封装有gpg解密的,于是就拿来用了。我的业务逻辑是取指定文件下的以.DAT结尾的gpg加密后的文件,然后遍历生成到制定的文件夹下。
在这其中遇到了两个坑。
1、业务逻辑中的方法中一定不要忘记加Security.addProvider(new BouncyCastleProvider());这一句,不然报错,人往往容易一叶障目,这不该发生的问题让我找了好久。
2、报这个错误java.security.InvalidKeyException: Illegal key size or default parameters。问题原因是解密的私钥位数太长,跟jdk版本有关系。密钥长度是受限制的, java运行时环境读到的是受限的policy文件. 文件位于${java_home}/jre/lib/security, 这种限制是因为美国对软件出口的控制。在jdk的版本中在jdk1.8的151版本之后就解除了这种限制。当时在本地测试的一切顺利,一发布到测试环境就有问题,后来了解测试环境的jdk版本是jdk1.8的121版本,还是有秘钥长度的限制。相关介绍:https://my.oschina.net/u/1037605/blog/3026103。
首先是maven要引用的jar包。
下面就是代码了(复制粘贴就可以用了,前提你要有相应的秘钥信息)。
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.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.sinosoft.light.dataswitch.service.util.PGPExampleUtil;
import com.sinosoft.platform.common.exception.SinoSystemException;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.bcpg.CompressionAlgorithmTags;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPCompressedData;
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;
public class KeyBasedFileProcessor {
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 (oinstanceof 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);
Object message = plainFact.nextObject();
if (messageinstanceof PGPCompressedData) {
PGPCompressedData cData = (PGPCompressedData) message;
JcaPGPObjectFactory pgpFact =new JcaPGPObjectFactory(cData.getDataStream());
message = pgpFact.nextObject();
}
if (messageinstanceof PGPLiteralData) {
PGPLiteralData ld = (PGPLiteralData) message;
String outFileName = ld.getFileName();
if (outFileName.length() ==0) {
outFileName = defaultFileName;
}else {
outFileName = defaultFileName;
}
InputStream unc = ld.getInputStream();
OutputStream fOut =new BufferedOutputStream(new FileOutputStream(outFileName));
Streams.pipeAll(unc, fOut);
fOut.close();
}else if (messageinstanceof 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 {
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 ListReadFileName()throws SinoSystemException {
File f =null;
// DateUtil.getCurrentDate("yyyy-MM-dd");
// String timerandom = DateUtil.getCurrentDate("yyyy-MM-dd").replace("-", "");
String path ="";
// path = "D:" + "/" + timerandom + "/encrypt";
path ="D:/20190628/encrypt/";
f =new File(path); //新建文件实例
File[] list = f.listFiles(); /* 此处获取文件夹下的所有文件 */
List fileNameList =new ArrayList();
if (null != list && list.length >0) {
for (int i =0; i < list.length; i++) {
fileNameList.add(list[i].getName());
System.out.println("遍历后的文件名:" + fileNameList.get(i));
}
}else {
throw new SinoSystemException("文件夹没有相应的文件");
}
return fileNameList;
}
//主方法
public static void main(String[] s)throws Exception {
Security.addProvider(new BouncyCastleProvider());
boolean encryp =false; //加密:true 解密:false
if (encryp) {
String outPath ="D:\\20190628\\decrypt\\123.DAT";
String inputPath ="D:\\20190628\\decrypt\\123.txt";
String publicKeys ="D:\\20190628\\public\\C3B655736E8C77F83183074049F3AB440C1B1830.asc"; //公钥地址
encryptFile(outPath, inputPath, publicKeys, true, true);
}else {
String inputPath;
String outPath;
String address ="D:/20190628/decrypt/";
String password ="1234568987"; //私钥的Key
String privateKeys ="D:\\20190628\\private\\C3B655736E8C77F83183074049F3AB440C1B1830.asc";//私钥地址
//批量解密文件
List fileList =ReadFileName();
if (null != fileList) {
for (int i =0; i < fileList.size(); i++) {
inputPath ="D:/20190628/encrypt/" + fileList.get(i); //被加密的文件
if (fileList.get(i).indexOf("DAT") != -1) {
outPath = address + fileList.get(i).replace("DAT", "TXT");
System.out.println("解密第一个文件,要解密的文件:" + inputPath +",解密出来的文件" + outPath);
decryptFile(inputPath, privateKeys, password.toCharArray(), outPath);
}else {
continue;
}
}
}
}
}
}
----------------------------------------------------------------------------
import org.bouncycastle.openpgp.*;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
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;
public 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 PGPPrivateKeyfindSecretKey(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 PGPPublicKeyreadPublicKey(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 PGPPublicKeyreadPublicKey(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 PGPSecretKeyreadSecretKey(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 PGPSecretKeyreadSecretKey(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.");
}
}