当前位置: 首页 > 知识库问答 >
问题:

使用Java xml数字签名API的xml签名的摘要值错误

农飞尘
2023-03-14

我需要发送一个签名的XML文件到巴西的一个政府机构。问题是,我的Java代码(使用Java XML数字签名API)计算的摘要与使用另一个工具(如XMLSec)生成的摘要不同。

下面是我用来为某个XML节点生成XML签名的代码:

private synchronized void sign(XmlObject obj) throws Exception {
        initKeystore();
        XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
        List<Transform> transformList = new ArrayList<Transform>();
        Transform envelopedTransform = fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null);
        Transform c14NTransform = fac.newTransform("http://www.w3.org/TR/2001/REC-xml-c14n-20010315",
                (TransformParameterSpec) null);
        transformList.add(envelopedTransform);
        transformList.add(c14NTransform);
        Reference ref = fac.newReference("", fac.newDigestMethod(DigestMethod.SHA1, null),
                Collections.singletonList(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)), null,
                null);
        SignedInfo si = fac.newSignedInfo(
                fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null),
                fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null), Collections.singletonList(ref));
        KeyStore ks = KeyStore.getInstance("PKCS12");
        ks.load(new FileInputStream(System.getProperty("javax.net.ssl.keyStore")),
                System.getProperty("javax.net.ssl.keyStorePassword").toCharArray());
        KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry("entry",
                new KeyStore.PasswordProtection(System.getProperty("javax.net.ssl.keyStorePassword").toCharArray()));

        X509Certificate cert = (X509Certificate) keyEntry.getCertificate();

        // Create the KeyInfo containing the X509Data.
        KeyInfoFactory kif = fac.getKeyInfoFactory();
        X509Data xd = kif.newX509Data(Collections.singletonList(cert));
        KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd));
        // Instantiate the document to be signed.

        Element el = (Element) obj.getDomNode().getFirstChild();
        String id = el.getAttribute("Id");

        DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), el);
        // Create the XMLSignature, but don't sign it yet.
        XMLSignature signature = fac.newXMLSignature(si, ki);
        // Marshal, generate, and sign the enveloped signature.
        signature.sign(dsc);

    }

如果尝试使用xmlsec验证生成的XML,则会出现以下错误:

$ xmlsec1 --verify consulta.xml 
func=xmlSecOpenSSLEvpDigestVerify:file=digests.c:line=229:obj=sha1:subj=unknown:error=12:invalid data:data and digest do not match
FAIL

但如果我尝试使用xmlsec(使用相同的私钥)对同一文件(consult.xml)进行签名,则错误就会消失:

xmlsec1 --sign --output doc-signed.xml --privkey-pem cert.pem consulta.xml

consult.xml和doc-Signed.xml(由xmlsec生成)之间的区别在于SignatureValue和DigestValue标记的内容:

<DigestValue>Ajn+tfX7JQc0HPNJ8KbTy7Q2f8I=</DigestValue>
...
<SignatureValue>Q1Ys0Rtj8yL2SA2NaQWQPtmNuHKK8q2anPiyLWlH7mOIjwOs0GEcD0WLUM/BZU0Q
T0kSbDTuJeTR2Ec9wu+hqXXbJ76FpX9/IyHrdyx2hLg0VhB5RRCdyBEuGlmnsFDf
XCyBotP+ZyEzolbTCN9TjCUnXNDWtFP1YapMxAIA0sth0lTpYgGJd8CSvFlHdFj+
ourf8ZGiDmSTkVkKnqDsj8O0ZLmbZfJpH2CBKicX+Ct7MUz2sqVli4XAHs6WXX+E
HJpbOKthS3WCcpG3Kw4K50yIYGTkTbWCYFxOVsMfiVy4W/Qz15Vxb8chD8LM58Ep
m/szmvnTAESxv/piDr7hyw==</SignatureValue>
<DigestValue>w6xElXJrZw3G86OsNkWav+pcKJo=</DigestValue>
...
<SignatureValue>YmUsnlnAY9uLhlfVBLhB8K8ArxMOkOKZJoQ6zgz55ggU6vJCO9+HWJCKQJp6Rvn/w5PCAFY0KJRb
r6/WhHML0Z+Q6TSuIL8OTvJ3iPoROAK6uy07YAflKOUklqk4uxgfMkR+hWMCyfITJVCVZo/MXmPy
g7YwmztoSlGH+p6+ND5n2u47Y2k6SpIvw3CUxwAVQkD0Hsj3G58cbUbrFCoyPVGOe4zJ9c1HPsMW
KzBEFe3QETzPJ8I1B7EEVi5oDvzXE2rMTH4K7zvNGnXpBNGwnSjEOticlqKVP5wyUD7CPwgF1Wgy
Z0njvlaW3K8YmAY8fc70v/+wSO6Fu+0zj18Xeg==</SignatureValue>

据我所知,接收这个XML文件的web应用程序是一个.NET应用程序,它计算的签名摘要与我的Java代码不同(很像xmlsec)。有什么想法吗?

共有1个答案

南门茂才
2023-03-14

如果还来得及回答:

您在代码中创建了2个转换(envelopedTransform和c14NTransform),但不使用它们。

使用一个新的Transform.Enveloped创建引用。http://www.w3.org/tr/2001/rec-xml-c14n-20010315(C14N)转换未应用。

现在,我不确定XML安全标准对这种情况下的行为应该是什么。也许其他工具也会自动应用C14N转换。

基本上更改fac.newReference(“”,...),并将transformList传递到其中,而不是Collections.SingletonList()。

 类似资料:
  • 我有一个关于计算PDF文档摘要以用于数字签名的快速问题(与我前面的一个问题有点相关,我试图弄清楚为什么您需要知道客户的证书以创建正确的摘要)。在Adobe关于PDF格式的文档中,指定了以下内容: 字节范围摘要应在文件中的一个字节范围内计算,该范围应由签名字典中的字节范围条目指示。这个范围应该是整个文件,包括签名字典,但不包括签名值本身(内容条目)。 因此,在这一点上,事情似乎相当简单,只需消化除/

  • 我正在尝试为PDF签名执行以下设置,将其分解为客户端和服务器之间的异步步骤: null 我所做的基本上是将该摘要发送给客户机进行签名,然后在服务器上重做上述步骤并设置客户机签名: 此设置最终导致文件完整性被破坏,因为在服务器上嵌入后,我要创建一个新的PDSignature。有没有一种方法可以序列化调用addSignature后创建的PDDocument,这样我以后就可以在服务器上反序列化它并添加客

  • 我做了两个应该做同样事情的实现:用给定的X509证书对XML文件进行签名。 null null

  • 我想用PHP实现一个XML数字签名。我正在这个验证器上测试签名的正确性。 我得到了错误的签名值,所以我要一步一步地解释我在做什么,请纠正我做错了什么。 我要签名的XML(无新行): 首先,我规范化XML,然后使用sha256对其进行散列,从而生成正确的摘要值。 第二,创建SignedInfo XML元素并规范化它(无新行): 最后,使用RSA-SHA256对SignedInfo元素进行签名。这是产

  • 本文向大家介绍浅析java消息摘要与数字签名,包括了浅析java消息摘要与数字签名的使用技巧和注意事项,需要的朋友参考一下 消息摘要 算法简述 定义 它是一个唯一对应一个消息或文本的固定长度的值,它由一个单向Hash加密函数对消息进行作用而产生。如果消息在途中改变了,则接收者通过对收到消息的新产生的摘要与原摘要比较,就可知道消息是否被改变了。因此消息摘要保证了消息的完整性。消息摘要采用单向Hash

  • 我正在尝试使用远程web服务来演唱pdf,该服务返回一个XML签名,该签名由签名和最终用户证书组成。 我需要使用此签名通过IText签名对pdf进行签名,因为web服务。 所有IText示例都使用消息格式,但我不确定应该如何处理XML签名。 打开临时Pdf并嵌入接收到的签名的代码 从web服务返回的XML签名: 当我将返回的签名与上面的代码一起使用时,签名验证失败,出现“错误遇到时BER解码”。