【问题标题】:Questions on Java XML Digital SignatureJava XML 数字签名问题
【发布时间】:2015-01-13 04:05:39
【问题描述】:

我需要对 XML 文档进行数字签名。给出的要求是输入是一个 XML 文件和一个私钥。签名应该使用 SHA256/RSA-2048,并且签名应该是 Enveloping。我想出了以下方法来做到这一点。在测试中,使用 KeyPairGenerator 类生成 KeyPair,其中 RSA 作为算法,密钥大小设置为 2048。传递的输入流是 FileInputStream 对象,输出流是 FileOutputStream 对象。该方法似乎工作正常。

public void sign(InputStream inputStream, OutputStream outputStream, KeyPair kp) throws Exception {
    XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");

    Reference ref = fac.newReference("#object", fac.newDigestMethod(DigestMethod.SHA256, null));

    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setNamespaceAware(true);
    org.w3c.dom.Document doc = dbf.newDocumentBuilder().parse(inputStream);
    XMLStructure content = new DOMStructure(doc.getDocumentElement());
    XMLObject obj = fac.newXMLObject(Collections.singletonList(content), "object", null, null);

    SignatureMethod signatureMethod = fac.newSignatureMethod("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", null);
    CanonicalizationMethod canonicalizationMethod = fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec)null);

    SignedInfo si = fac.newSignedInfo(canonicalizationMethod, signatureMethod, Collections.singletonList(ref));

    KeyInfoFactory kif = fac.getKeyInfoFactory();
    KeyValue kv = kif.newKeyValue(kp.getPublic());

    KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));

    XMLSignature signature = fac.newXMLSignature(si, ki, Collections.singletonList(obj), null, null);

    DOMSignContext dsc = new DOMSignContext(kp.getPrivate(), doc);

    signature.sign(dsc);

    TransformerFactory tf = TransformerFactory.newInstance();
    Transformer trans = tf.newTransformer();
    trans.transform(new DOMSource(doc), new StreamResult(outputStream));       
}

我有一些问题:

  1. 我没有在代码中指定应该在签名中使用 RSA,那么它是如何知道的呢?另外,我知道在加密中,还有模式和填充。同样,这些也没有指定,那么它们是什么?

  2. 我真的不知道 XML 的规范化是如何工作的。 CanonicalizationMethod.INCLUSIVE 和 CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS 都产生相同的输出(都具有相同的 DigestValue 值)。这些不同的方法是什么意思?

  3. 对象标签中的封装消息似乎与输入的 XML 文件内容完全相同。封装的消息应该与原始 XML 相同还是应该是规范化的版本?我知道摘要中使用了规范化版本,但不确定是否应该规范化封装版本。我的原始 XML 有 cmets 标签,但无论我输入 INCLUSIVE 还是 INCLUSIVE_WITH_COMMENTS,cmets 标签都会出现在输出中。

  4. 是否需要公钥?给我的要求是私钥是一个输入,但我不确定我是否也应该询问公钥。 KeyValue 对象似乎需要公钥。

提前致谢。

【问题讨论】:

    标签: java encryption key digital-signature xml-signature


    【解决方案1】:

    1) 签名算法是从您与 newSignatureMethod ("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256") 一起使用的 URI 中推断出来的

    2) 您没有为 newReference 中的 Reference 指定任何规范化算法。因此,在计算 XML 数据的摘要值之前使用默认值(没有 cmets 的规范 XML)。您的 canonicalizationMethod 与 SignedInfo 一起使用:在计算签名值之前,将使用此算法对 SignedInfo 元素进行规范化。

    要为已签名的 XML 数据指定规范化算法,您需要在创建参考时说明:

    Transform tr = fac.newTransform(CanonicalizationMethod.INCLUSIVE, (TransformParameterSpec) null);
    
    fac.newReference("#object", fac.newDigestMethod(DigestMethod.SHA256, null), Collections.singletonList(tr), null, null);
    

    此代码将使用规范化算法在引用中添加一个转换,引用将被散列的#object。

    3) 您将在 Object 元素中拥有与添加到其中的内容完全相同的内容。在计算摘要值之前,将对该内容应用规范化(或任何其他转换)。

    4) KeyValue 是可选的,是签名验证者的提示。通常的签名将证书放在 X509Certificate 中,而不是密钥值。

    希望这会有所帮助。 莫兹

    【讨论】:

    • 我不太明白您对 (2) 的回答。调用 newReference() 方法有什么问题吗?
    • 如果我在这一行更改规范化算法: CanonicalizationMethod canonicalizationMethod = signatureFactory.newCanonicalizationMethod(CanonicalizationMethod.EXCLUSIVE_WITH_COMMENTS, (C14NMethodParameterSpec)null);我注意到 DigestValue 仍然保持不变,但 SignatureValue 会改变。为什么会这样?
    • CanonicalizationMethod 指定了一种规范化算法,该算法将用于在计算签名值之前对 SignedInfo 进行规范化。对 XML blob 的摘要值没有影响。我在答案中添加了为 XML blob 添加规范化算法的方式。
    • 加密时可以指定模式和填充。例如,RSA/ECB/PKCS1Padding。对于数字签名,我使用的是 RSA。那么是否已经内置了默认模式和填充?我们可以指定模式和填充吗?
    • 填充和附加参数在 URI 中是隐含的。 URI w3.org/2001/04/xmldsig-more#rsa-sha256 指的是 RFC 3447 中描述的 RSASSA-PKCS1-v1_5 算法(请参阅 w3.org/TR/xmldsig-core1/#sec-PKCS1)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-14
    • 2011-08-17
    • 1970-01-01
    相关资源
    最近更新 更多