javaxmldsig和XPath

javaxmldsig和XPath,java,xml-signature,Java,Xml Signature,我正在使用JavaXMLDSIGAPI对XML文档的一部分进行签名。我试图理解它是如何得到摘要值的 我的文件是: <?xml version=\"1.0\" encoding=\"UTF-8\"?><PurchaseOrder><foo>bar</foo></PurchaseOrder> 我想做的是: 调用JavaDSIG库并查看生成摘要的值 使用MessageDigest(SHA-1)类对值“bar”进行摘要 验证1和2的摘要是否匹

我正在使用JavaXMLDSIGAPI对XML文档的一部分进行签名。我试图理解它是如何得到摘要值的

我的文件是:

<?xml version=\"1.0\" encoding=\"UTF-8\"?><PurchaseOrder><foo>bar</foo></PurchaseOrder>
我想做的是:

  • 调用JavaDSIG库并查看生成摘要的值
  • 使用MessageDigest(SHA-1)类对值“bar”进行摘要
  • 验证1和2的摘要是否匹配
  • 当我这样做时,1和2生成不同的摘要值。要么我的DSIG代码完全出了问题,要么我不明白DSIG是如何工作的。有什么想法吗

    这是我的测试代码(抱歉太长了…我应该回到perl):

    公共类GenerateXmlSignature2{
    私有静态最终字符串xml=“bar”;
    私有静态最终字符串xpath=“PurchaseOrder/foo/text()”;
    公共静态void main(字符串[]args)引发异常{
    Base64 Base64=新的Base64();
    //创建一个DOM XMLSignatureFactory,用于
    //生成封装的签名。
    最终XMLSignatureFactory fac=XMLSignatureFactory.getInstance(“DOM”);
    //创建对封装文档的引用(在本例中,
    //您正在对整个文档进行签名,因此URI为“”表示
    //并且还指定了SHA1摘要算法和
    //包络变换。
    最终列表xpaths=newarraylist(){
    {
    添加(新的XPathType(xpath,XPathType.Filter.UNION));
    }
    };
    列表转换=新建ArrayList(){{
    添加(fac.newTransform)(
    Transform.XPATH2,
    新的XPathFilter2ParameterSpec(xpaths)
    )
    );
    }};
    Reference ref=fac.newReference
    (“”,fac.newDigestMethod(DigestMethod.SHA1,null),
    转变,
    空,空);
    //创建SignedInfo。
    SignedInfo si=fac.newSignedInfo
    (fac.newcanonicalization方法)
    (CanonicalizationMethod.INCLUSIVE,
    (C14NMethodParameterSpec)null),
    fac.newSignatureMethod(SignatureMethod.RSA_SHA1,空),
    集合。单音列表(ref));
    //加载密钥库并获取签名密钥和证书。
    KeyStore ks=KeyStore.getInstance(“JKS”);
    load(新文件输入流(“mykeystore.jks”),“changeit.toCharArray());
    KeyStore.PrivateKeyEntry密钥入口=
    (KeyStore.PrivateKeyEntry)ks.getEntry
    (“mykey”,新的KeyStore.PasswordProtection(“changeit.toCharArray());
    X509Certificate cert=(X509Certificate)keyEntry.getCertificate();
    //创建包含X509数据的KeyInfo。
    KeyInfoFactory kif=fac.getKeyInfoFactory();
    List x509Content=new ArrayList();
    x509Content.add(cert.getSubjectX500Principal().getName());
    x509Content.add(证书);
    X509Data xd=kif.newX509Data(x509Content);
    KeyInfo ki=kif.newKeyInfo(Collections.singletonList(xd));
    //实例化要签名的文档。
    DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
    dbf.setNamespaceAware(true);
    Document doc=dbf.newDocumentBuilder().parse
    (新的ByteArrayInputStream(xml.getBytes());
    //创建DOMSignContext并指定RSA PrivateKey和
    //结果XMLSignature的父元素的位置。
    DOMSignContext dsc=新的DOMSignContext
    (keyEntry.getPrivateKey(),doc.getDocumentElement());
    //创建XMLSignature,但不要对其进行签名。
    XMLSignature signature=fac.newXMLSignature(si,ki);
    //封送、生成和签名封装的签名。
    签名。签名(dsc);
    //输出结果文档。
    TransformerFactory tf=TransformerFactory.newInstance();
    变压器变压器=tf.新变压器();
    trans.transform(新的DOMSource(doc)、新的StreamResult(System.out));
    System.out.println(“\n\n***SHA-1摘要***”);
    XPathExpression XPathExpression=XPathFactory.newInstance().newXPath().compile(xpath);
    String data=xpathExpression.evaluate(新的InputSource(新的StringReader(xml));
    System.out.println(“Xpath:+数据”);
    信息文摘md;
    md=MessageDigest.getInstance(“SHA”);
    字节[]sha1hash;
    md.update(data.getBytes(),0,data.length());
    sha1hash=md.digest();
    String base64Sha1OfCanonicalXml=新字符串(base64.encode(sha1hash));
    System.out.println(“摘要:“+base64Sha1OfCanonicalXml”);
    }
    }
    
    下面的例子是:,我发现我需要将
    XPathType.Filter.UNION
    更改为
    XPathType.Filter.INTERSECT
    。这似乎解决了我的问题。XML DSig库现在使用了我期望的正确值

    PurchaseOrder/foo/text()
    
    public class GenerateXmlSignature2 {
        private static final String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><PurchaseOrder><foo>bar</foo></PurchaseOrder>";
        private static final String xpath  = "PurchaseOrder/foo/text()";
    
        public static void main(String[] args) throws Exception {
            Base64 base64 = new Base64();
            // Create a DOM XMLSignatureFactory that will be used to
            // generate the enveloped signature.
            final XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
    
            // Create a Reference to the enveloped document (in this case,
            // you are signing the whole document, so a URI of "" signifies
            // that, and also specify the SHA1 digest algorithm and
            // the ENVELOPED Transform.
            final List<XPathType> xpaths = new ArrayList<XPathType>() {
                {
                    add(new XPathType(xpath, XPathType.Filter.UNION));
                }
            };
            List<Transform> transforms = new ArrayList<Transform>() {{
                 add(fac.newTransform(
                    Transform.XPATH2,
                    new XPathFilter2ParameterSpec(xpaths)
                )
                );
            }};
            Reference ref = fac.newReference
                    ("", fac.newDigestMethod(DigestMethod.SHA1, null),
                            transforms,
                            null, null);
    
    
            // Create the SignedInfo.
            SignedInfo si = fac.newSignedInfo
                    (fac.newCanonicalizationMethod
                            (CanonicalizationMethod.INCLUSIVE,
                                    (C14NMethodParameterSpec) null),
                            fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null),
                            Collections.singletonList(ref));
    
    
            // Load the KeyStore and get the signing key and certificate.
            KeyStore ks = KeyStore.getInstance("JKS");
            ks.load(new FileInputStream("mykeystore.jks"), "changeit".toCharArray());
            KeyStore.PrivateKeyEntry keyEntry =
                    (KeyStore.PrivateKeyEntry) ks.getEntry
                            ("mykey", new KeyStore.PasswordProtection("changeit".toCharArray()));
            X509Certificate cert = (X509Certificate) keyEntry.getCertificate();
    
            // Create the KeyInfo containing the X509Data.
            KeyInfoFactory kif = fac.getKeyInfoFactory();
            List x509Content = new ArrayList();
            x509Content.add(cert.getSubjectX500Principal().getName());
            x509Content.add(cert);
            X509Data xd = kif.newX509Data(x509Content);
            KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd));
    
            // Instantiate the document to be signed.
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            dbf.setNamespaceAware(true);
            Document doc = dbf.newDocumentBuilder().parse
                    (new ByteArrayInputStream(xml.getBytes()));
    
            // Create a DOMSignContext and specify the RSA PrivateKey and
            // location of the resulting XMLSignature's parent element.
            DOMSignContext dsc = new DOMSignContext
                    (keyEntry.getPrivateKey(), doc.getDocumentElement());
    
            // 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);
    
            // Output the resulting document.
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer trans = tf.newTransformer();
            trans.transform(new DOMSource(doc), new StreamResult(System.out));
    
    
    
            System.out.println("\n\n*** SHA-1 Digest ***");
            XPathExpression xpathExpression = XPathFactory.newInstance().newXPath().compile(xpath);
            String data = xpathExpression.evaluate(new InputSource(new StringReader(xml)));
            System.out.println("Xpath: " + data);
            MessageDigest md;
            md = MessageDigest.getInstance("SHA");
            byte[] sha1hash;
            md.update(data.getBytes(), 0, data.length());
            sha1hash = md.digest();
            String base64Sha1OfCanonicalXml = new String(base64.encode(sha1hash));
            System.out.println("Digest:   " + base64Sha1OfCanonicalXml);
        }
    }