From 5a2c94a32cebace8b53925f67014aed850e23115 Mon Sep 17 00:00:00 2001 From: cheney Date: Fri, 22 May 2026 10:57:29 +0800 Subject: [PATCH] =?UTF-8?q?=E8=8E=AB=E5=90=8D=E5=A5=87=E5=A6=99=E7=9A=84?= =?UTF-8?q?=E9=AA=8C=E7=AD=BE=E6=88=90=E5=8A=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/sunyard/cisd/device/tool/CMSUtil.java | 141 ++++++++++++++---- 1 file changed, 110 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/sunyard/cisd/device/tool/CMSUtil.java b/src/main/java/com/sunyard/cisd/device/tool/CMSUtil.java index 516f9c8..a413695 100644 --- a/src/main/java/com/sunyard/cisd/device/tool/CMSUtil.java +++ b/src/main/java/com/sunyard/cisd/device/tool/CMSUtil.java @@ -314,6 +314,11 @@ public class CMSUtil { 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(); @@ -487,40 +492,31 @@ public class CMSUtil { System.out.println(" 签名值 (Hex): " + bytesToHex(signatureValue)); System.out.println(" signedAttrs 数据类型: " + authAttrsData.getClass().getName()); - String[] algNames = {"SM3withSM2", "SHA256withSM2", "SM2"}; + byte[] signingData = signedAttrsEncoded; boolean valid = false; - for (String algName : algNames) { - try { - Signature signature = Signature.getInstance(algName, "BC"); - signature.initVerify(signerCert.getPublicKey()); - signature.update(signedAttrsEncoded); - valid = signature.verify(signatureValue); - System.out.println(" 算法 " + algName + " 验签结果: " + (valid ? "成功" : "失败")); - if (valid) break; - } catch (Exception e) { - System.out.println(" 算法 " + algName + " 失败: " + e.getMessage()); - } - } - if (!valid) { - System.out.println("\n [调试] 尝试使用原始签名值格式验签..."); - try { - Signature signature = Signature.getInstance("SM3withSM2", "BC"); - signature.initVerify(signerCert.getPublicKey()); - signature.update(signedAttrsEncoded); - byte[] rawSig = new byte[64]; - if (signatureValue.length >= 65 && signatureValue[0] == 0x30) { - int offset = signatureValue[1] >= 0x81 ? (signatureValue[1] == 0x81 ? 3 : 2) : 2; - if (signatureValue.length >= offset + 32 + 2) { - System.arraycopy(signatureValue, offset + 1, rawSig, 0, 32); - System.arraycopy(signatureValue, offset + 33, rawSig, 32, 32); - valid = signature.verify(rawSig); - System.out.println(" 原始格式验签结果: " + (valid ? "成功" : "失败")); - } - } - } catch (Exception e) { - System.out.println(" 原始格式验签失败: " + e.getMessage()); + 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, @@ -693,6 +689,89 @@ public class CMSUtil { throw new Exception("未找到有效的签名信息"); } + private static boolean verifySM2Signature(PublicKey publicKey, byte[] data, byte[] signature) { + try { + Signature sig = Signature.getInstance("SM3withSM2", "BC"); + sig.initVerify(publicKey); + sig.update(data); + boolean result = sig.verify(signature); + System.out.println(" 验签结果: " + (result ? "成功" : "失败")); + + if (!result && data.length > 0 && data[0] == 0x30) { + System.out.println(" [GMT 0010-2012] 尝试将SEQUENCE转换为SET..."); + byte[] setData = convertSequenceToSet(data); + if (setData != null) { + sig = Signature.getInstance("SM3withSM2", "BC"); + sig.initVerify(publicKey); + sig.update(setData); + result = sig.verify(signature); + System.out.println(" SET格式验签结果: " + (result ? "成功" : "失败")); + } + } + + return result; + } catch (Exception e) { + System.out.println(" 验签失败: " + e.getMessage()); + return false; + } + } + + 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 void main(String[] args) { if (args.length < 1) { System.out.println("用法: java CMSUtil ");