javaxml数字签名问题

javaxml数字签名问题,java,encryption,key,digital-signature,xml-signature,Java,Encryption,Key,Digital Signature,Xml Signature,我需要对XML文档进行数字签名。给出的要求是输入是一个XML文件和一个私钥。签名应使用SHA256/RSA-2048,签名应为信封式。我已经想出了下面的方法来做到这一点。在测试中,使用KeyPairGenerator类生成密钥对,RSA作为算法,密钥大小设置为2048。传递的输入流是FileInputStream对象,输出流是FileOutputStream对象。这个方法似乎很有效 public void sign(InputStream inputStream, OutputStream ou

我需要对XML文档进行数字签名。给出的要求是输入是一个XML文件和一个私钥。签名应使用SHA256/RSA-2048,签名应为信封式。我已经想出了下面的方法来做到这一点。在测试中,使用KeyPairGenerator类生成密钥对,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));       
}
我有一些问题:

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

  • 我真的不知道XML的规范化是如何工作的。带有注释的CanonicalizationMethod.INCLUSIVE和CanonicalizationMethod.INCLUSIVE_生成相同的输出(两者具有相同的DigestValue)。这些不同的方法意味着什么

  • 对象标记中封装的消息似乎与输入XML文件内容完全相同。封装的消息应该与原始XML相同,还是应该是规范化版本?我知道摘要中使用了规范化版本,但不确定封装的版本是否应该规范化。我的原始XML有comments标记,但是comments标记将始终出现在输出中,无论我是使用INCLUSIVE还是INCLUSIVE_加上_注释

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

  • 提前感谢。

    1)签名算法是从您在newSignatureMethod(“”)中使用的URI推断出来的

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

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

    Transform tr = fac.newTransform(CanonicalizationMethod.INCLUSIVE, (TransformParameterSpec) null);
    
    fac.newReference("#object", fac.newDigestMethod(DigestMethod.SHA256, null), Collections.singletonList(tr), null, null);
    
    这段代码将在引用将被散列的#对象的引用中添加一个带有规范化算法的转换

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

    4) KeyValue是可选的,是签名验证器的提示。通常签名将在X509Certificate中包含证书,而不是键值

    希望这有帮助。
    Moez

    我真的不明白你对(2)的回答。调用newReference()方法有什么问题吗?如果我更改此行中的规范化算法:CanonicalizationMethod CanonicalizationMethod=signatureFactory.newCanonicalizationMethod(CanonicalizationMethod.EXCLUSIVE_,带_注释,(C14NMethodParameterSpec)null);我注意到DigestValue仍将保持不变,但SignatureValue将更改。为什么会这样?规范化方法指定了一个规范化算法,该算法将用于在计算签名值之前规范化SignedInfo。对XML blob的摘要值没有影响。我在答案中添加了为XML blob添加规范化算法的方法。当我们进行加密时,我们可以指定模式和填充。例如,RSA/ECB/PKCS1P。对于数字签名,我使用RSA。那么,是否已经内置了默认模式和填充?我们可以指定模式和填充吗?填充和其他参数是URI中隐含的。URI指RFC 3447中描述的RSASSA-PKCS1-v1_5算法(请参阅)。