javaxmldsig和XPath
我正在使用JavaXMLDSIGAPI对XML文档的一部分进行签名。我试图理解它是如何得到摘要值的 我的文件是: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的摘要是否匹
<?xml version=\"1.0\" encoding=\"UTF-8\"?><PurchaseOrder><foo>bar</foo></PurchaseOrder>
我想做的是:
公共类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);
}
}