java pkcs7格式签名工具

Posted ppybk

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java pkcs7格式签名工具相关的知识,希望对你有一定的参考价值。

package com.xxx.util;

import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.bouncycastle.asn1.DEROutputStream;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.*;
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.util.Store;

/**
* PKCS7Tool.java pkcs7格式签名工具,读取证书密钥进行加密
*
* @version 1.0
* @author Written Date: 2020-01-03
* JDK
*/
public class PKCS7Tool {
/** 签名证书链 */
static X509Certificate[] certificates = null;
/** 签名私钥 */
static PrivateKey privateKey = null;
/** 根证书 */
//private Certificate rootCertificate = null;
/** 证书存放路径 */
static String keyStorePath = "C:\upload\cert.pfx";
/** 证书密码 */
static String keyStorePassword = "..";
/** JVM 提供商 */
private static char jvm = 0;
private static Class algorithmId = null;
private static Class derValue = null;
private static Class objectIdentifier = null;
private static Class x500Name = null;
private static boolean debug = false;
private static BouncyCastleProvider bouncyCastleProvider = null;

static {
try {
//如果是PKCS7Padding填充方式,则必须加上下面这行
if (bouncyCastleProvider == null) {
bouncyCastleProvider = new BouncyCastleProvider();
}
Security.addProvider(bouncyCastleProvider);
init();
// 加载证书库
KeyStore keyStore = null;
if (keyStorePath.toLowerCase().endsWith(".pfx"))
keyStore = KeyStore.getInstance("PKCS12");
else
keyStore = KeyStore.getInstance("JKS");
FileInputStream fis = null;
try {
fis = new FileInputStream(keyStorePath);
keyStore.load(fis, keyStorePassword.toCharArray());
} finally {
if (fis != null)
fis.close();
}
// 在证书库中找到签名私钥
Enumeration aliases = keyStore.aliases();
String keyAlias = null;
if (aliases != null) {
while (aliases.hasMoreElements()) {
keyAlias = (String) aliases.nextElement();
Certificate[] certs = keyStore.getCertificateChain(keyAlias);
if (certs == null || certs.length == 0)
continue;
X509Certificate cert = (X509Certificate) certs[0];
if (matchUsage(cert.getKeyUsage(), 1)) {
try {
cert.checkValidity();
} catch (CertificateException e) {
continue;
}
break;
}
}
}
// 没有找到可用签名私钥
if (keyAlias == null)
throw new GeneralSecurityException(
"None certificate for sign in this keystore");
if (debug)
System.out.println(keyAlias);
if (keyStore.isKeyEntry(keyAlias)) {
// 检查证书链
Certificate[] certs = keyStore.getCertificateChain(keyAlias);
for (int i = 0; i < certs.length; i++) {
if (!(certs[i] instanceof X509Certificate))
throw new GeneralSecurityException("Certificate[" + i
+ "] in chain ‘" + keyAlias
+ "‘ is not a X509Certificate.");
}
// 转换证书链
certificates = new X509Certificate[certs.length];
for (int i = 0; i < certs.length; i++)
certificates[i] = (X509Certificate) certs[i];
} else if (keyStore.isCertificateEntry(keyAlias)) {
// 只有单张证书
Certificate cert = keyStore.getCertificate(keyAlias);
if (cert instanceof X509Certificate) {
certificates = new X509Certificate[ { (X509Certificate) cert }];
}
} else {
throw new GeneralSecurityException(keyAlias
+ " is unknown to this keystore");
}
privateKey = (PrivateKey) keyStore.getKey(keyAlias,
keyStorePassword.toCharArray());
// 没有私钥抛异常
if (privateKey == null) {
throw new GeneralSecurityException(keyAlias
+ " could not be accessed");
}
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 签名
*
* @param data
* 数据
* @return signature 签名结果
* @throws GeneralSecurityException
* @throws IOException
* @throws IllegalArgumentException
*/
public static String sign(byte[] data) throws Exception {
X509Certificate cerx509 = certificates[0];
List<X509Certificate> certList = new ArrayList<X509Certificate>();
certList.add(cerx509);
Store certs = new JcaCertStore(certList);
ContentSigner contentSigner = new JcaContentSignerBuilder(cerx509.getSigAlgName()).setProvider("BC").build(privateKey);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(
new JcaDigestCalculatorProviderBuilder().setProvider("BC")
.build()).setDirectSignature(true).build(contentSigner, cerx509));
gen.addCertificates(certs);
CMSTypedData msg = new CMSProcessableByteArray(data);
CMSSignedData sigData = gen.generate(msg, false);
org.bouncycastle.asn1.cms.ContentInfo a = sigData.toASN1Structure();
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
try{
DEROutputStream dOut = new DEROutputStream(bOut);
dOut.writeObject(a);
return Base64.encodeBase64String(bOut.toByteArray());
}finally{
IOUtils.closeQuietly(bOut);
}
}

/**
* 验证签名(无CRL)
*
* @param data
* 被签名数据
* @param signature
* 签名签名结果
* @throws Exception
*/
public static boolean verify(byte[] data, byte[] signature) throws Exception {
CMSProcessable content = new CMSProcessableByteArray(data);
//新建PKCS#7签名数据处理对象
CMSSignedData s = new CMSSignedData(content, signature);
Store certStore = s.getCertificates();
//获得签名者信息
SignerInformationStore signers = s.getSignerInfos();
Iterator<?> it = signers.getSigners().iterator();
int verified = 0, size = 0;
//当有多个签名者信息时需要全部验证
while (it.hasNext()) {
size++;
SignerInformation signer = (SignerInformation) it.next();
//证书链
Collection<?> certCollection = certStore.getMatches(signer.getSID());
Iterator<?> certIt = certCollection.iterator();
X509CertificateHolder cert = (X509CertificateHolder) certIt.next();
//验证数字签名
if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert))) {
verified++;
}
}
if (verified >0 && size == verified) {
return true;
}
return false;
}


/**
* 匹配私钥用法
*
* @param keyUsage
* @param usage
* @return
*/
private static boolean matchUsage(boolean[] keyUsage, int usage) {
if (usage == 0 || keyUsage == null)
return true;
for (int i = 0; i < Math.min(keyUsage.length, 32); i++) {
if ((usage & (1 << i)) != 0 && !keyUsage[i])
return false;
}
return true;
}


private static void init() {
if (jvm != 0)
return;
String vendor = System.getProperty("java.vm.vendor");
if (vendor == null)
vendor = "";
String vendorUC = vendor.toUpperCase();
try {
if (vendorUC.indexOf("SUN") >= 0) {
jvm = ‘S‘;
algorithmId = Class.forName("sun.security.x509.AlgorithmId");
derValue = Class.forName("sun.security.util.DerValue");
objectIdentifier = Class.forName("sun.security.util.ObjectIdentifier");
x500Name = Class.forName("sun.security.x509.X500Name");
} else if (vendorUC.indexOf("ORACLE CORPORATION") >= 0) {
jvm = ‘O‘;
algorithmId = Class.forName("sun.security.x509.AlgorithmId");
derValue = Class.forName("sun.security.util.DerValue");
objectIdentifier = Class.forName("sun.security.util.ObjectIdentifier");
x500Name = Class.forName("sun.security.x509.X500Name");
} else if (vendorUC.indexOf("IBM") >= 0) {
jvm = ‘I‘;
algorithmId = Class.forName("com.ibm.security.x509.AlgorithmId");
derValue = Class.forName("com.ibm.security.util.DerValue");
objectIdentifier = Class.forName("com.ibm.security.util.ObjectIdentifier");
x500Name = Class.forName("com.ibm.security.x509.X500Name");
} else {
System.out.println("Not support JRE: " + vendor);
System.exit(-1);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
System.exit(-1);
}
}

}

相关jar包:compile group: ‘org.bouncycastle‘, name: ‘bcpkix-jdk15on‘, version: ‘1.52‘

以上是关于java pkcs7格式签名工具的主要内容,如果未能解决你的问题,请参考以下文章

openssl验证签名错误,但命令行工具没问题

在 python 中获取 PKCS7 签名者链

从 php 中的 PKCS7 签名中提取证书

如何使用 openssl 或任何其他在智能卡上签名的库创建 PKCS7 signedData 结构?

使用 AES-256 和 PKCS7 填充加密

从不透明的 pkcs7 p7m 转换为分离的 smime