seckit4j/src/main/java/com/sunyard/cisd/device/tool/CMSUtil.java
2026-06-23 11:29:46 +08:00

830 lines
49 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.sunyard.cisd.device.tool;
import org.bouncycastle.asn1.*;
import org.bouncycastle.asn1.cms.*;
import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
import org.bouncycastle.asn1.cms.ContentInfo;
import org.bouncycastle.asn1.x509.Certificate;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cms.*;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Store;
import java.security.*;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Base64;
import java.util.Collection;
public class CMSUtil {
static {
Security.addProvider(new BouncyCastleProvider());
}
public static String detectCMSType(String base64CmsData) throws Exception {
byte[] cmsData = Base64.getDecoder().decode(base64CmsData);
return detectCMSType(cmsData);
}
public static String detectCMSType(byte[] cmsData) throws Exception {
try (ASN1InputStream asn1InputStream = new ASN1InputStream(cmsData)) {
ContentInfo contentInfo = ContentInfo.getInstance(asn1InputStream.readObject());
String typeOid = contentInfo.getContentType().getId();
if (typeOid.equals(CMSObjectIdentifiers.signedData.getId())) {
return "SignedData";
} else if (typeOid.equals(CMSObjectIdentifiers.envelopedData.getId())) {
return "EnvelopedData";
} else if (typeOid.equals(CMSObjectIdentifiers.signedAndEnvelopedData.getId())) {
return "SignedAndEnvelopedData";
} else if (typeOid.equals(CMSObjectIdentifiers.digestedData.getId())) {
return "DigestedData";
} else if (typeOid.equals(CMSObjectIdentifiers.encryptedData.getId())) {
return "EncryptedData";
} else {
return "Unknown: " + typeOid;
}
}
}
public static boolean verifySignedData(String base64CmsData) throws Exception {
byte[] cmsData = Base64.getDecoder().decode(base64CmsData);
return verifySignedData(cmsData);
}
public static boolean verifySignedData(byte[] cmsData) throws Exception {
CMSSignedData cmsSignedData = new CMSSignedData(cmsData);
return verifySignedData(cmsSignedData);
}
public static boolean verifySignedData(CMSSignedData cmsSignedData) throws Exception {
Store certStore = cmsSignedData.getCertificates();
SignerInformationStore signerStore = cmsSignedData.getSignerInfos();
for (Object signerObj : signerStore.getSigners()) {
SignerInformation signer = (SignerInformation) signerObj;
Collection certCollection = certStore.getMatches(signer.getSID());
if (certCollection.isEmpty()) {
System.err.println("未找到签名证书");
continue;
}
X509CertificateHolder certHolder = (X509CertificateHolder) certCollection.iterator().next();
X509Certificate cert = convertCertificate(certHolder);
try {
if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert))) {
return true;
}
} catch (Exception e) {
System.err.println("签名验证失败: " + e.getMessage());
}
}
return false;
}
public static boolean verifySignedDataWithCertificate(String base64CmsData, X509Certificate publicCert) throws Exception {
byte[] cmsData = Base64.getDecoder().decode(base64CmsData);
CMSSignedData cmsSignedData = new CMSSignedData(cmsData);
return verifySignedDataWithCertificate(cmsSignedData, publicCert);
}
public static boolean verifySignedDataWithCertificate(CMSSignedData cmsSignedData, X509Certificate publicCert) throws Exception {
SignerInformationStore signerStore = cmsSignedData.getSignerInfos();
for (Object signerObj : signerStore.getSigners()) {
SignerInformation signer = (SignerInformation) signerObj;
try {
if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(publicCert))) {
return true;
}
} catch (Exception e) {
System.err.println("使用指定证书验证失败: " + e.getMessage());
}
}
return false;
}
public static byte[] extractSignedContent(String base64CmsData) throws Exception {
byte[] cmsData = Base64.getDecoder().decode(base64CmsData);
CMSSignedData cmsSignedData = new CMSSignedData(cmsData);
return (byte[]) cmsSignedData.getSignedContent().getContent();
}
public static X509Certificate loadCertificateFromBytes(byte[] certBytes) throws Exception {
CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
return (X509Certificate) cf.generateCertificate(new java.io.ByteArrayInputStream(certBytes));
}
public static X509Certificate loadCertificateFromBase64(String base64Cert) throws Exception {
byte[] certBytes = Base64.getDecoder().decode(base64Cert);
return loadCertificateFromBytes(certBytes);
}
private static X509Certificate convertCertificate(X509CertificateHolder certHolder) throws Exception {
CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
return (X509Certificate) cf.generateCertificate(new java.io.ByteArrayInputStream(certHolder.getEncoded()));
}
public static class SignedAndEnvelopedVerifyResult {
public final boolean signatureValid;
public final byte[] messageDigest;
public final X509Certificate signerCertificate;
public final String signerSubjectDN;
public SignedAndEnvelopedVerifyResult(boolean signatureValid, byte[] messageDigest,
X509Certificate signerCertificate, String signerSubjectDN) {
this.signatureValid = signatureValid;
this.messageDigest = messageDigest;
this.signerCertificate = signerCertificate;
this.signerSubjectDN = signerSubjectDN;
}
}
public static SignedAndEnvelopedVerifyResult verifySignedAndEnvelopedData(String base64CmsData) throws Exception {
byte[] cmsData = Base64.getDecoder().decode(base64CmsData);
return verifySignedAndEnvelopedData(cmsData);
}
private static X509Certificate tryParseCertificate(ASN1Encodable elem) {
try {
if (elem instanceof ASN1Sequence) {
Certificate cert = Certificate.getInstance(elem);
byte[] certEncoded = cert.getEncoded();
return loadCertificateFromBytes(certEncoded);
}
} catch (Exception e) {
}
return null;
}
public static SignedAndEnvelopedVerifyResult verifySignedAndEnvelopedData(byte[] cmsData) throws Exception {
System.out.println("[步骤1] 解析 ContentInfo...");
ASN1InputStream asn1InputStream = new ASN1InputStream(cmsData);
ContentInfo contentInfo = ContentInfo.getInstance(asn1InputStream.readObject());
System.out.println(" ContentInfo 解析成功");
System.out.println(" OID: " + contentInfo.getContentType().getId());
if (!contentInfo.getContentType().equals(CMSObjectIdentifiers.signedAndEnvelopedData)) {
throw new Exception("不是 SignedAndEnvelopedData 格式");
}
System.out.println("[步骤2] 解析 SignedAndEnvelopedData 结构...");
ASN1Primitive contentPrimitive = contentInfo.getContent().toASN1Primitive();
System.out.println(" Content 类型: " + contentPrimitive.getClass().getSimpleName());
ASN1Sequence saeSequence = ASN1Sequence.getInstance(contentPrimitive);
System.out.println(" SignedAndEnvelopedData 包含 " + saeSequence.size() + " 个元素");
int index = 0;
ASN1Integer version = ASN1Integer.getInstance(saeSequence.getObjectAt(index++).toASN1Primitive());
System.out.println(" 版本: " + version.getValue());
ASN1Set recipientInfos = ASN1Set.getInstance(saeSequence.getObjectAt(index++).toASN1Primitive());
System.out.println(" RecipientInfos 数量: " + recipientInfos.size());
System.out.println(" 检查后续元素,寻找证书和签名信息...");
X509Certificate signerCert = null;
byte[] signedAttrsEncoded = null;
byte[] signatureValue = null;
for (int i = index; i < saeSequence.size(); i++) {
ASN1Encodable elemEncodable = saeSequence.getObjectAt(i);
ASN1Primitive elem = elemEncodable.toASN1Primitive();
System.out.println("\n 检查第" + (i+1) + "个元素,类型: " + elem.getClass().getSimpleName());
if (elem instanceof ASN1Set) {
ASN1Set set = ASN1Set.getInstance(elem);
System.out.println(" DLSet 包含 " + set.size() + " 个元素");
for (int si = 0; si < set.size(); si++) {
ASN1Encodable setElem = set.getObjectAt(si);
System.out.println(" DLSet[" + si + "] 类型: " + setElem.toASN1Primitive().getClass().getSimpleName());
X509Certificate cert = tryParseCertificate(setElem);
if (cert != null) {
signerCert = cert;
System.out.println(" 从DLSet[" + si + "] 找到证书!");
System.out.println(" 证书主题: " + signerCert.getSubjectX500Principal().getName());
break;
}
if (setElem.toASN1Primitive() instanceof ASN1Sequence) {
ASN1Sequence innerSeq = ASN1Sequence.getInstance(setElem);
for (int j = 0; j < innerSeq.size(); j++) {
cert = tryParseCertificate(innerSeq.getObjectAt(j));
if (cert != null) {
signerCert = cert;
System.out.println(" 从DLSet[" + si + "]的嵌套序列找到证书!");
System.out.println(" 证书主题: " + signerCert.getSubjectX500Principal().getName());
break;
}
}
}
}
}
if (elem instanceof ASN1Sequence) {
ASN1Sequence seq = ASN1Sequence.getInstance(elem);
System.out.println(" 序列包含 " + seq.size() + " 个元素");
for (int j = 0; j < seq.size(); j++) {
ASN1Encodable subElem = seq.getObjectAt(j);
ASN1Primitive subPrim = subElem.toASN1Primitive();
System.out.println(" 子元素 " + j + ": " + subPrim.getClass().getSimpleName());
X509Certificate cert = tryParseCertificate(subElem);
if (cert != null) {
signerCert = cert;
System.out.println(" 从子元素 " + j + " 找到证书!");
System.out.println(" 证书主题: " + signerCert.getSubjectX500Principal().getName());
break;
}
if (subPrim instanceof ASN1Sequence) {
ASN1Sequence subSeq = ASN1Sequence.getInstance(subPrim);
for (int k = 0; k < subSeq.size(); k++) {
cert = tryParseCertificate(subSeq.getObjectAt(k));
if (cert != null) {
signerCert = cert;
System.out.println(" 从子元素 " + j + " 的嵌套序列[" + k + "]找到证书!");
System.out.println(" 证书主题: " + signerCert.getSubjectX500Principal().getName());
break;
}
}
}
if (signerCert != null) break;
}
}
if (elem instanceof ASN1TaggedObject) {
ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(elem);
System.out.println(" TaggedObject 标签编号: " + tagged.getTagNo());
ASN1Primitive innerPrim = tagged.getObject();
System.out.println(" 内部对象类型: " + innerPrim.getClass().getSimpleName());
X509Certificate cert = tryParseCertificate(tagged.getObject());
if (cert != null) {
signerCert = cert;
System.out.println(" 从TaggedObject找到证书!");
System.out.println(" 证书主题: " + signerCert.getSubjectX500Principal().getName());
}
if (innerPrim instanceof ASN1Sequence) {
ASN1Sequence innerSeq = ASN1Sequence.getInstance(innerPrim);
for (int j = 0; j < innerSeq.size(); j++) {
cert = tryParseCertificate(innerSeq.getObjectAt(j));
if (cert != null) {
signerCert = cert;
System.out.println(" 从TaggedObject的内部序列[" + j + "]找到证书!");
System.out.println(" 证书主题: " + signerCert.getSubjectX500Principal().getName());
break;
}
}
}
}
if (signerCert != null) break;
}
if (signerCert == null) {
throw new Exception("数字信封中未找到有效的签名者证书");
}
System.out.println("\n[步骤3] 提取签名者证书 - 成功");
System.out.println(" 签名者主题: " + signerCert.getSubjectX500Principal().getName());
System.out.println(" 公钥算法: " + signerCert.getPublicKey().getAlgorithm());
System.out.println(" 证书签名算法: " + signerCert.getSigAlgName());
System.out.println("\n[步骤4] 解析 SignerInfo...");
for (int i = index; i < saeSequence.size(); i++) {
ASN1Primitive elem = saeSequence.getObjectAt(i).toASN1Primitive();
if (elem instanceof ASN1Set) {
ASN1Set signerInfosSet = ASN1Set.getInstance(elem);
System.out.println(" SignerInfos 包含 " + signerInfosSet.size() + " 个元素");
for (int si = 0; si < signerInfosSet.size(); si++) {
System.out.println("\n 处理第 " + (si+1) + " 个 SignerInfo...");
ASN1Encodable signerInfoEncodable = signerInfosSet.getObjectAt(si);
ASN1Primitive signerInfoPrim = signerInfoEncodable.toASN1Primitive();
byte[] signerInfoDer = signerInfoPrim.getEncoded(ASN1Encoding.DER);
System.out.println(" SignerInfo DER 编码长度: " + signerInfoDer.length + " bytes");
System.out.println(" SignerInfo DER 编码: " + bytesToHex(signerInfoDer));
System.out.println(" SignerInfo 原始类型: " + signerInfoPrim.getClass().getSimpleName());
String signerInfoPrimClassName = signerInfoPrim.getClass().getName();
System.out.println(" SignerInfo 原始类型: " + signerInfoPrimClassName);
System.out.println(" 是 ASN1Sequence: " + (signerInfoPrim instanceof ASN1Sequence));
System.out.println(" 是 ASN1TaggedObject: " + (signerInfoPrim instanceof ASN1TaggedObject));
System.out.println(" 类名包含 TaggedObject: " + signerInfoPrimClassName.contains("TaggedObject"));
if (signerInfoPrim instanceof ASN1Sequence) {
ASN1Sequence signerInfoSeq = ASN1Sequence.getInstance(signerInfoPrim);
System.out.println(" SignerInfo 包含 " + signerInfoSeq.size() + " 个元素");
for (int el = 0; el < signerInfoSeq.size(); el++) {
ASN1Encodable elEnc = signerInfoSeq.getObjectAt(el);
System.out.println(" 元素 " + el + ": " + elEnc.toASN1Primitive().getClass().getSimpleName());
}
if (signerInfoSeq.size() < 4) {
System.out.println(" SignerInfo 元素数量不足,跳过");
continue;
}
int signerIndex = 0;
ASN1Integer signerVersion = ASN1Integer.getInstance(signerInfoSeq.getObjectAt(signerIndex++).toASN1Primitive());
System.out.println(" Signer 版本: " + signerVersion.getValue());
System.out.println(" SignerIdentifier 解析成功");
ASN1Sequence digestAlgorithm = ASN1Sequence.getInstance(signerInfoSeq.getObjectAt(signerIndex++).toASN1Primitive());
System.out.println(" DigestAlgorithm 解析成功");
ASN1Encodable authAttrsData = null;
System.out.println(" 检查 AuthenticatedAttributes (signedAttrs)...");
boolean foundAuthenticatedAttributes = false;
while (signerIndex < signerInfoSeq.size() && !foundAuthenticatedAttributes) {
ASN1Encodable authAttrsObj = signerInfoSeq.getObjectAt(signerIndex);
String elemClassName = authAttrsObj.getClass().getName();
boolean isTaggedObject = elemClassName.contains("TaggedObject");
boolean isSet = (authAttrsObj instanceof ASN1Set);
boolean isSequence = (authAttrsObj instanceof ASN1Sequence);
System.out.println(" 检查元素 " + signerIndex + " 类型: " + elemClassName);
if (isSet) {
authAttrsData = authAttrsObj;
System.out.println(" 发现 SET 类型 AuthenticatedAttributes");
foundAuthenticatedAttributes = true;
} else if (isTaggedObject) {
ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(authAttrsObj);
int tagNo = tagged.getTagNo();
System.out.println(" 发现 TaggedObject标签: " + tagNo);
ASN1Encodable innerObj = tagged.getObject();
System.out.println(" 内部对象类型: " + innerObj.getClass().getName());
if (innerObj instanceof ASN1Set) {
authAttrsData = innerObj;
System.out.println(" 从 TaggedObject[" + tagNo + "] 提取 SET");
foundAuthenticatedAttributes = true;
} else if (innerObj instanceof ASN1Sequence) {
ASN1Sequence innerSeq = ASN1Sequence.getInstance(innerObj);
System.out.println(" TaggedObject[" + tagNo + "] 内部是 Sequence包含: " + innerSeq.size());
if (tagNo == 0 && innerSeq.size() > 0) {
System.out.println(" 从标签[0]的 Sequence 提取 AuthenticatedAttributes包含: " + innerSeq.size() + " 个属性");
// 使用原始的 DLTaggedObject 获取 DER 编码,而不是从 innerSeq 重新编码
authAttrsData = tagged;
foundAuthenticatedAttributes = true;
signerIndex++;
System.out.println(" 找到 AuthenticatedAttributessignerIndex 递增到: " + signerIndex);
} else {
System.out.println(" 标签[" + tagNo + "] 不是 AuthenticatedAttributes (应为[0]),跳过");
}
}
if (!foundAuthenticatedAttributes) {
signerIndex++;
}
} else if (isSequence) {
System.out.println(" Sequence 类型: " + elemClassName + ",跳过");
signerIndex++;
} else {
System.out.println(" 未知类型: " + elemClassName + ",跳过");
signerIndex++;
}
}
if (signerIndex >= signerInfoSeq.size()) {
System.out.println(" AuthenticatedAttributes 为空,跳过");
continue;
}
ASN1Sequence digestEncryptionAlgorithm = ASN1Sequence.getInstance(signerInfoSeq.getObjectAt(signerIndex++).toASN1Primitive());
System.out.println(" DigestEncryptionAlgorithm 解析成功");
if (signerIndex >= signerInfoSeq.size()) {
System.out.println(" EncryptedDigest 不存在");
continue;
}
ASN1OctetString encryptedDigest = ASN1OctetString.getInstance(signerInfoSeq.getObjectAt(signerIndex));
System.out.println(" EncryptedDigest 长度: " + encryptedDigest.getOctets().length + " bytes");
if (authAttrsData == null) {
System.out.println(" AuthenticatedAttributes 为空,跳过验签");
continue;
}
System.out.println("\n[步骤5] 提取待签名数据 (signedAttrs DER 编码)...");
signedAttrsEncoded = authAttrsData.toASN1Primitive().getEncoded(ASN1Encoding.DER);
System.out.println(" signedAttrs DER 编码长度: " + signedAttrsEncoded.length + " bytes");
System.out.println(" signedAttrs Hex: " + bytesToHex(signedAttrsEncoded));
System.out.println("\n[步骤6] 提取原文 Hash (message-digest 属性,仅打印不参与运算)...");
byte[] messageDigest = null;
ASN1EncodableVector authAttrsVector = new ASN1EncodableVector();
if (authAttrsData instanceof ASN1Set) {
ASN1Set authSet = (ASN1Set) authAttrsData;
for (int j = 0; j < authSet.size(); j++) {
authAttrsVector.add(authSet.getObjectAt(j));
}
} else if (authAttrsData instanceof ASN1Sequence) {
ASN1Sequence authSeq = (ASN1Sequence) authAttrsData;
for (int j = 0; j < authSeq.size(); j++) {
authAttrsVector.add(authSeq.getObjectAt(j));
}
} else if (authAttrsData instanceof ASN1TaggedObject) {
ASN1TaggedObject tagged = (ASN1TaggedObject) authAttrsData;
ASN1Primitive inner = tagged.getObject();
if (inner instanceof ASN1Sequence) {
ASN1Sequence authSeq = (ASN1Sequence) inner;
for (int j = 0; j < authSeq.size(); j++) {
authAttrsVector.add(authSeq.getObjectAt(j));
}
}
}
for (int j = 0; j < authAttrsVector.size(); j++) {
ASN1Sequence attrSeq = ASN1Sequence.getInstance(authAttrsVector.get(j).toASN1Primitive());
if (attrSeq.size() < 2) {
continue;
}
ASN1ObjectIdentifier attrType = ASN1ObjectIdentifier.getInstance(attrSeq.getObjectAt(0));
if (attrType.equals(CMSAttributes.messageDigest)) {
ASN1Encodable attrValues = attrSeq.getObjectAt(1);
ASN1Primitive attrValuesPrim = attrValues.toASN1Primitive();
if (attrValuesPrim instanceof ASN1Set) {
ASN1Set valuesSet = ASN1Set.getInstance(attrValuesPrim);
if (valuesSet.size() > 0) {
messageDigest = ASN1OctetString.getInstance(valuesSet.getObjectAt(0)).getOctets();
System.out.println(" message-digest 值 (Hex): " + bytesToHex(messageDigest));
System.out.println(" message-digest 长度: " + messageDigest.length + " bytes");
}
} else if (attrValuesPrim instanceof ASN1OctetString) {
messageDigest = ((ASN1OctetString) attrValuesPrim).getOctets();
System.out.println(" message-digest 值 (Hex): " + bytesToHex(messageDigest));
System.out.println(" message-digest 长度: " + messageDigest.length + " bytes");
}
}
}
signatureValue = encryptedDigest.getOctets();
System.out.println("\n[步骤7] 使用 SM2 算法验签 signedAttrs DER 编码...");
System.out.println(" DigestEncryptionAlgorithm OID: " +
((ASN1ObjectIdentifier)digestEncryptionAlgorithm.getObjectAt(0)).getId());
System.out.println(" 签名值长度: " + signatureValue.length + " bytes");
System.out.println(" 签名值 (Hex): " + bytesToHex(signatureValue));
System.out.println(" signedAttrs 数据类型: " + authAttrsData.getClass().getName());
byte[] signingData = signedAttrsEncoded;
boolean valid = false;
if (authAttrsData instanceof ASN1TaggedObject) {
System.out.println(" [GMT 0010-2012] 尝试使用两种方式验签:");
System.out.println("\n 方式1: 使用带标签的完整编码 (包含 [0] IMPLICIT 标签)");
valid = verifySM2Signature(signerCert.getPublicKey(), signingData, signatureValue);
if (!valid) {
System.out.println("\n 方式2: 使用标签内的原始数据 (不包含标签)");
ASN1TaggedObject tagged = (ASN1TaggedObject) authAttrsData;
ASN1Primitive inner = tagged.getObject();
byte[] innerEncoded = inner.getEncoded(ASN1Encoding.DER);
System.out.println(" 内部数据长度: " + innerEncoded.length + " bytes");
System.out.println(" 内部数据 Hex: " + bytesToHex(innerEncoded));
valid = verifySM2Signature(signerCert.getPublicKey(), innerEncoded, signatureValue);
}
} else {
valid = verifySM2Signature(signerCert.getPublicKey(), signingData, signatureValue);
}
if (!valid) {
System.out.println("\n [调试] 尝试调整签名值格式...");
valid = tryAlternativeFormats(signerCert.getPublicKey(), signingData, signatureValue);
}
return new SignedAndEnvelopedVerifyResult(valid, messageDigest, signerCert,
signerCert.getSubjectX500Principal().getName());
} else if (signerInfoPrim instanceof ASN1TaggedObject) {
ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(signerInfoPrim);
System.out.println(" TaggedObject 标签: " + tagged.getTagNo());
System.out.println(" 内部对象类型: " + tagged.getObject().getClass().getSimpleName());
ASN1Primitive inner = tagged.getObject();
if (inner instanceof ASN1Sequence) {
ASN1Sequence signerInfoSeq = ASN1Sequence.getInstance(inner);
System.out.println(" SignerInfo 包含 " + signerInfoSeq.size() + " 个元素");
if (signerInfoSeq.size() >= 4) {
int signerIndex = 0;
ASN1Integer signerVersion = ASN1Integer.getInstance(signerInfoSeq.getObjectAt(signerIndex++).toASN1Primitive());
System.out.println(" Signer 版本: " + signerVersion.getValue());
System.out.println(" SignerIdentifier 解析成功");
ASN1Sequence digestAlgorithm = ASN1Sequence.getInstance(signerInfoSeq.getObjectAt(signerIndex++).toASN1Primitive());
System.out.println(" DigestAlgorithm 解析成功");
ASN1Set authenticatedAttributes = null;
System.out.println(" 检查 AuthenticatedAttributes (signedAttrs)...");
while (signerIndex < signerInfoSeq.size()) {
ASN1Encodable authAttrsObj = signerInfoSeq.getObjectAt(signerIndex);
ASN1Primitive authAttrsPrim = authAttrsObj.toASN1Primitive();
System.out.println(" 检查元素 " + signerIndex + " 类型: " + authAttrsPrim.getClass().getName());
if (authAttrsPrim instanceof ASN1TaggedObject || authAttrsPrim.getClass().getName().contains("TaggedObject")) {
ASN1TaggedObject authTagged = ASN1TaggedObject.getInstance(authAttrsObj);
System.out.println(" 标签编号: " + authTagged.getTagNo());
ASN1Primitive authInner = authTagged.getObject();
System.out.println(" 内部对象类型: " + authInner.getClass().getName());
if (authInner instanceof ASN1Set) {
authenticatedAttributes = ASN1Set.getInstance(authInner);
System.out.println(" AuthenticatedAttributes (tagged) 发现 " + authenticatedAttributes.size() + " 个属性");
signerIndex++;
break;
} else if (authInner instanceof ASN1Sequence) {
authenticatedAttributes = ASN1Set.getInstance(authInner);
System.out.println(" AuthenticatedAttributes (tagged sequence) 发现 " + authenticatedAttributes.size() + " 个属性");
signerIndex++;
break;
}
} else if (authAttrsPrim instanceof ASN1Set) {
authenticatedAttributes = ASN1Set.getInstance(authAttrsPrim);
System.out.println(" AuthenticatedAttributes 发现 " + authenticatedAttributes.size() + " 个属性");
signerIndex++;
break;
} else if (authAttrsPrim instanceof ASN1Sequence) {
authenticatedAttributes = ASN1Set.getInstance(authAttrsPrim);
System.out.println(" AuthenticatedAttributes (sequence) 发现 " + authenticatedAttributes.size() + " 个属性");
signerIndex++;
break;
} else {
System.out.println(" 不是 AuthenticatedAttributes 类型: " + authAttrsPrim.getClass().getName() + ",跳过");
signerIndex++;
}
}
if (signerIndex >= signerInfoSeq.size()) {
System.out.println(" AuthenticatedAttributes 为空,跳过");
continue;
}
ASN1Sequence digestEncryptionAlgorithm = ASN1Sequence.getInstance(signerInfoSeq.getObjectAt(signerIndex++).toASN1Primitive());
System.out.println(" DigestEncryptionAlgorithm 解析成功");
if (signerIndex >= signerInfoSeq.size()) {
System.out.println(" EncryptedDigest 不存在");
continue;
}
ASN1Encodable sigElement = signerInfoSeq.getObjectAt(signerIndex);
ASN1Primitive sigPrim = sigElement.toASN1Primitive();
System.out.println(" 签名元素类型: " + sigPrim.getClass().getSimpleName());
byte[] encryptedDigestBytes = null;
if (sigPrim instanceof ASN1OctetString) {
encryptedDigestBytes = ((ASN1OctetString) sigPrim).getOctets();
} else if (sigPrim instanceof ASN1TaggedObject) {
ASN1TaggedObject sigTagged = ASN1TaggedObject.getInstance(sigPrim);
if (sigTagged.getObject() instanceof ASN1OctetString) {
encryptedDigestBytes = ((ASN1OctetString) sigTagged.getObject()).getOctets();
}
} else if (sigPrim instanceof ASN1Sequence) {
ASN1Sequence sigSeq = ASN1Sequence.getInstance(sigPrim);
if (sigSeq.size() > 0) {
ASN1Encodable lastElem = sigSeq.getObjectAt(sigSeq.size() - 1);
if (lastElem instanceof ASN1OctetString) {
encryptedDigestBytes = ((ASN1OctetString) lastElem).getOctets();
}
}
}
if (encryptedDigestBytes == null) {
System.out.println(" 无法解析签名值");
continue;
}
System.out.println(" EncryptedDigest 长度: " + encryptedDigestBytes.length + " bytes");
if (authenticatedAttributes == null) {
System.out.println(" AuthenticatedAttributes 为空,跳过验签");
continue;
}
System.out.println("\n[步骤5] 提取待签名数据 (signedAttrs DER 编码)...");
signedAttrsEncoded = authenticatedAttributes.getEncoded(ASN1Encoding.DER);
System.out.println(" signedAttrs DER 编码长度: " + signedAttrsEncoded.length + " bytes");
System.out.println(" signedAttrs Hex: " + bytesToHex(signedAttrsEncoded));
System.out.println("\n[步骤6] 提取原文 Hash (message-digest 属性,仅打印不参与运算)...");
byte[] messageDigest = null;
for (int j = 0; j < authenticatedAttributes.size(); j++) {
ASN1Sequence attrSeq = ASN1Sequence.getInstance(authenticatedAttributes.getObjectAt(j).toASN1Primitive());
if (attrSeq.size() < 2) {
continue;
}
ASN1ObjectIdentifier attrType = ASN1ObjectIdentifier.getInstance(attrSeq.getObjectAt(0));
if (attrType.equals(CMSAttributes.messageDigest)) {
ASN1Encodable attrValues = attrSeq.getObjectAt(1);
ASN1Primitive attrValuesPrim = attrValues.toASN1Primitive();
if (attrValuesPrim instanceof ASN1Set) {
ASN1Set valuesSet = ASN1Set.getInstance(attrValuesPrim);
if (valuesSet.size() > 0) {
messageDigest = ASN1OctetString.getInstance(valuesSet.getObjectAt(0)).getOctets();
System.out.println(" message-digest 值 (Hex): " + bytesToHex(messageDigest));
System.out.println(" message-digest 长度: " + messageDigest.length + " bytes");
}
} else if (attrValuesPrim instanceof ASN1OctetString) {
messageDigest = ((ASN1OctetString) attrValuesPrim).getOctets();
System.out.println(" message-digest 值 (Hex): " + bytesToHex(messageDigest));
System.out.println(" message-digest 长度: " + messageDigest.length + " bytes");
}
}
}
signatureValue = encryptedDigestBytes;
System.out.println("\n[步骤7] 使用 SM2 算法验签 signedAttrs DER 编码...");
Signature signature = Signature.getInstance("SM3withSM2", "BC");
signature.initVerify(signerCert.getPublicKey());
signature.update(signedAttrsEncoded);
System.out.println(" 签名值长度: " + signatureValue.length + " bytes");
System.out.println(" 签名值 (Hex): " + bytesToHex(signatureValue));
boolean valid = signature.verify(signatureValue);
System.out.println(" 验签结果: " + (valid ? "成功" : "失败"));
return new SignedAndEnvelopedVerifyResult(valid, messageDigest, signerCert,
signerCert.getSubjectX500Principal().getName());
}
}
} else {
System.out.println(" 未知类型,跳过");
}
}
}
}
throw new Exception("未找到有效的签名信息");
}
private static boolean verifySM2Signature(PublicKey publicKey, byte[] data, byte[] signature) {
try {
System.out.println(" ┌─────────────────────────────────────────────────────");
System.out.println(" │ 验签输入信息");
System.out.println(" ├─────────────────────────────────────────────────────");
System.out.println(" │ [输入1] 原始数据 (DER编码):");
System.out.println(" │ 长度: " + data.length + " bytes");
System.out.println(" │ Hex: " + bytesToHex(data));
System.out.println(" ├─────────────────────────────────────────────────────");
System.out.println(" │ [输入2] 公钥:");
System.out.println(" │ 算法: " + publicKey.getAlgorithm());
System.out.println(" │ 格式: " + publicKey.getFormat());
System.out.println(" │ 编码长度: " + publicKey.getEncoded().length + " bytes");
System.out.println(" │ Hex: " + bytesToHex(truncate(publicKey.getEncoded(), 64)));
System.out.println(" ├─────────────────────────────────────────────────────");
System.out.println(" │ [输入3] 签名值:");
System.out.println(" │ 长度: " + signature.length + " bytes");
System.out.println(" │ Hex: " + bytesToHex(signature));
System.out.println(" ├─────────────────────────────────────────────────────");
Signature sig = Signature.getInstance("SM3withSM2", "BC");
sig.initVerify(publicKey);
sig.update(data);
boolean result = sig.verify(signature);
System.out.println(" │ [输出] 验签结果: " + (result ? "成功" : "失败"));
System.out.println(" └─────────────────────────────────────────────────────");
if (!result && data.length > 0 && data[0] == 0x30) {
byte[] setData = convertSequenceToSet(data);
if (setData != null) {
System.out.println(" ┌─────────────────────────────────────────────────────");
System.out.println(" │ [GMT 0010-2012] 验签输入信息 (SET格式转换)");
System.out.println(" ├─────────────────────────────────────────────────────");
System.out.println(" │ [输入1] 原始数据 (SET格式):");
System.out.println(" │ 长度: " + setData.length + " bytes");
System.out.println(" │ Hex: " + bytesToHex(setData));
System.out.println(" ├─────────────────────────────────────────────────────");
System.out.println(" │ [输入2] 公钥:");
System.out.println(" │ 算法: " + publicKey.getAlgorithm());
System.out.println(" │ 格式: " + publicKey.getFormat());
System.out.println(" │ 编码长度: " + publicKey.getEncoded().length + " bytes");
System.out.println(" │ Hex: " + bytesToHex(truncate(publicKey.getEncoded(), 64)));
System.out.println(" ├─────────────────────────────────────────────────────");
System.out.println(" │ [输入3] 签名值:");
System.out.println(" │ 长度: " + signature.length + " bytes");
System.out.println(" │ Hex: " + bytesToHex(signature));
System.out.println(" ├─────────────────────────────────────────────────────");
sig = Signature.getInstance("SM3withSM2", "BC");
sig.initVerify(publicKey);
sig.update(setData);
result = sig.verify(signature);
System.out.println(" │ [输出] 验签结果: " + (result ? "成功" : "失败"));
System.out.println(" └─────────────────────────────────────────────────────");
}
}
return result;
} catch (Exception e) {
System.out.println(" ┌─────────────────────────────────────────────────────");
System.out.println(" │ [输出] 验签失败: " + e.getMessage());
System.out.println(" └─────────────────────────────────────────────────────");
return false;
}
}
private static byte[] truncate(byte[] data, int maxLength) {
if (data.length <= maxLength) {
return data;
}
byte[] truncated = new byte[maxLength];
System.arraycopy(data, 0, truncated, 0, maxLength);
return truncated;
}
private static byte[] convertSequenceToSet(byte[] sequenceData) {
try {
if (sequenceData.length < 2 || sequenceData[0] != 0x30) {
return null;
}
byte[] setData = new byte[sequenceData.length];
System.arraycopy(sequenceData, 0, setData, 0, sequenceData.length);
setData[0] = 0x31;
return setData;
} catch (Exception e) {
return null;
}
}
private static boolean tryAlternativeFormats(PublicKey publicKey, byte[] data, byte[] signature) {
try {
if (signature.length >= 65 && signature[0] == 0x30) {
System.out.println(" 尝试解析 ASN.1 编码的签名值...");
int offset = 2;
if (signature[1] >= 0x81) {
offset = signature[1] == 0x81 ? 3 : 2 + (signature[1] & 0xFF);
}
if (signature[offset] == 0x02) {
int rLen = signature[offset + 1];
byte[] r = new byte[rLen];
System.arraycopy(signature, offset + 2, r, 0, rLen);
offset += 2 + rLen;
if (signature[offset] == 0x02) {
int sLen = signature[offset + 1];
byte[] s = new byte[sLen];
System.arraycopy(signature, offset + 2, s, 0, sLen);
byte[] rawSig = new byte[64];
int rStart = r[0] == 0x00 ? 1 : 0;
int sStart = s[0] == 0x00 ? 1 : 0;
System.arraycopy(r, rStart, rawSig, 32 - r.length + rStart, r.length - rStart);
System.arraycopy(s, sStart, rawSig, 64 - s.length + sStart, s.length - sStart);
Signature sig = Signature.getInstance("SM3withSM2", "BC");
sig.initVerify(publicKey);
sig.update(data);
boolean result = sig.verify(rawSig);
System.out.println(" 原始格式(R+S)验签结果: " + (result ? "成功" : "失败"));
return result;
}
}
}
} catch (Exception e) {
System.out.println(" 尝试其他格式失败: " + e.getMessage());
}
return false;
}
public static String bytesToHex(byte[] data) {
StringBuilder sb = new StringBuilder();
for (byte b : data) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
}