是否可以创建自动将数字签名添加到xml内容的jaxb marshaller。
例如,如果我有一个定义的类:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Test {
@XmlElement
private String info;
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
由marshaller生成的我的xml看起来像:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><test><info>value</info></test>
我希望它看起来像:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Security>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"/>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#envelopedsignature"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>4432kZ6c2JPwP3A=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>Mvbd4603knhh2LZTyE1MIiEF7N46b7GoTzxsqs5eyIXYNG96MFPIMo+P6okzIPzRKrL2obpf3V4D/F0gw5vM/UJwb2MvrCo/5JM5qvV0f09dzWLrgkPyShiQnFL2vzECwmMOrCA=</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>MIIEnjCCBAegAwIBAgIDJQDMA0GCSqGSICBMGSETU0VOMRgwFgYDVQQHEw82NTAwOCBXaWVzYmFkZW4xGjAYBgNVBkESE9MRElORyBBRzEiMCAGA1UEAxMZSW50ZXJuZXQgQmVudXR6ZXIgU2VydmljZTEqMCgGCSqGSIb3DQEJARbeVydmaWthdEBzY2h1ZmEtb25saW5lLmRlMB4XDTA5MDcyNzEwNTkyNVoXDTEwMDcyNzEwNTkyNVowgZsxCzAJdNVBATAkFMQLmRlMCYGfUdEgQfMB2BG3plcnRpZmlrYXRAc2NodWZhLW9ubGluZS5kZTAfsgkqhkiG9w0BAQQFAAOBgQB7DBly8bqksxrkwcmN2A/xfu3lm0IfGD6PoJ7JFgPq4aHBDWgdUW3EzvRE+cuFGjkoBvATKfcbF7ReTz+4C+dLJShYiN/HxUnxgiO7R2y4c/I4pNnmlfQT261/dNlQ8Wm8pyUeMcr32fxvtoY4dqlQy7GePmrHpR3HE/dMRAd6gA==</X509Certificate>
</X509Data>
<KeyValue>
<RSAKeyValue>
<Modulus>1EN/UxtM2fLYxxDmSxgjSd10AzCxvZtNGAER9j3+OMqZjBXG9uLiZR+GbtOXbsDz3fyiwEfu/FDeeGGESppYAL5foQ72t2ztV5w2GLtTH0K+wrlImmvoTdl6bsdC7RXAsXVxtlkoG0xL7HGwZLvM=</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
</KeyValue>
</KeyInfo>
</Signature>
</Security>
<test><info>value</info></test>
我希望marshaller有办法做到这一点?如果没有,可能还有其他简单的方法来签署xml?
提前致谢
答案 0 :(得分:8)
您需要使用JAXB将域模型封送到DOM Document
,然后使用如下方法将签名应用于该模型:
import java.security.*;
import java.util.Collections;
import javax.xml.bind.*;
import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Test.class);
Test test = new Test();
test.setInfo("value");
Marshaller marshaller = jc.createMarshaller();
DOMResult domResult = new DOMResult();
marshaller.marshal(test, domResult);
String providerName = System.getProperty("jsr105Provider",
"org.jcp.xml.dsig.internal.dom.XMLDSigRI");
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM",
(Provider) Class.forName(providerName).newInstance());
Reference ref = fac.newReference("", fac.newDigestMethod(
DigestMethod.SHA1, null), Collections.singletonList(fac
.newTransform(Transform.ENVELOPED, (XMLStructure) null)), null,
null);
SignedInfo si = fac.newSignedInfo(fac.newCanonicalizationMethod(
CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS, (XMLStructure) null), fac
.newSignatureMethod(SignatureMethod.DSA_SHA1, null),
Collections.singletonList(ref));
KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
kpg.initialize(512);
KeyPair kp = kpg.generateKeyPair();
KeyInfoFactory kif = fac.getKeyInfoFactory();
KeyValue kv = kif.newKeyValue(kp.getPublic());
KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));
Document doc = (Document) domResult.getNode();
DOMSignContext dsc = new DOMSignContext(kp.getPrivate(),
doc.getDocumentElement());
XMLSignature signature = fac.newXMLSignature(si, ki);
signature.sign(dsc);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
DOMSource source = new DOMSource(domResult.getNode());
StreamResult result = new StreamResult(System.out);
t.transform(source, result);
}
}