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(" 找到 AuthenticatedAttributes,signerIndex 递增到: " + 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(); } }