二、 生成一个Enveloping签名
这一节讨论借助于JSR-105 API及其缺省实现来实现对invoice.xml文件的签名。
我们的示例中创建了一个enveloping签名。注意,当你想使用在一种detached或enveloped签名情形下时,也仅需对本例作一些细微修改。
下面,让我们分析程序Sign.java,它能够生成invoice.xml文件的XML签名。
public class Sign { public static void main(String[] args) throws Exception { String input = "./etc/invoice.xml "; String output = "./etc/signature.xml"; if (args.length > 2) { input = args[0]; output = args[1]; } //准备 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); //步骤1 String providerName = System.getProperty("jsr105Provider","org.jcp.XML.dsig.internal.dom.XMLDSigRI"); XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM",(Provider) Class.forName(providerName).newInstance()); //步骤2 Reference ref = fac.newReference("#invoice",fac.newDigestMethod(DigestMethod.SHA1, null)); //步骤3 Document XML = dbf.newDocumentBuilder().parse(new File(input)); Node invoice = XML.getDocumentElement(); XMLStructure content = new DOMStructure(invoice); XMLObject obj = fac.newXMLObject(Collections.singletonList(content),"invoice", null, null); //步骤4 SignedInfo si = fac.newSignedInfo(fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS, (C14NMethodParameterSpec) null), fac.newSignatureMethod(SignatureMethod.DSA_SHA1, null), Collections.singletonList(ref)); //步骤5,分为情形5.0或5.1 PrivateKey privateKey = null; //情形5.0 privateKey = KeyStoreInfo.getPrivateKey("./etc/bizkeystore","sp1234","kp1234", "biz"); //情形5.1,分为情形5.1.1或5.1.2
//情形5.1.1 //KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA"); //kpg.initialize(512); //KeyPair kp = kpg.generateKeyPair();
//情形5.1.2 // KeyPair kp = KeyStoreInfo.getKeyPair("./etc/bizkeystore", "sp1234", // "kp1234","biz");
//如果针对情形5.1,请去掉下面一行中的注释 // privateKey = kp.getPrivate();
//步骤6,分为情形6.0,6.1或6.2
//情形6.0,如果针对情形6.1或6.2也使用下面这一行 KeyInfo ki = null;
//如果针对情形6.1或6.2请去掉下面一行中的注释 // KeyInfoFactory kif = fac.getKeyInfoFactory();
//情形6.1 // KeyValue kv = kif.newKeyValue(kp.getPublic()); // ki = kif.newKeyInfo(Collections.singletonList(kv));
//情形6.2 // CertificateFactory cf = CertificateFactory.getInstance("X.509"); // FileInputStream fis = new FileInputStream("./etc/biz.cer"); // java.security.cert.Certificate cert = cf.generateCertificate(fis); // fis.close(); // X509Data x509d = kif.newX509Data(Collections.singletonList(cert)); // ki = kif.newKeyInfo(Collections.singletonList(x509d));
//步骤7 XMLSignature signature = fac.newXMLSignature(si, ki,Collections.singletonList(obj), null, null);
//步骤8 Document doc = dbf.newDocumentBuilder().newDocument(); DOMSignContext dsc = new DOMSignContext(privateKey, doc);
//步骤9 signature.sign(dsc); //转换成一个xml文档 TransformerFactory tf = TransformerFactory.newInstance(); Transformer trans = tf.newTransformer(); trans.transform(new DOMSource(doc),new StreamResult(new FileOutputStream(output))); } } |
为了试验这个程序,读者可以运行Ant目标签名-它将创建一个XML文档./etc/signature.xml。这就是所谓的XML签名。为了保持我们的代码更为整洁和集中,我们省略了分析XML和转换DOM树中所有相关的格式设置。结果是,signature.xml文件成为一个有些凌乱的文本文件。
现在,让我们详细分析一下这个程序来说明如何在JSR-105中对一个XML签名进行签名。
签名invoice.xm的过程可以分解为如下九个步骤。
【步骤1】加载一个XMLSignatureFactory实例。这个工厂类将负责构建几乎所有主要的对象-我们在JSR-105中API中处理XML签名时需要使用这些对象,除了那些与KeyInfo相关的对象之外。
【步骤2】选择一个digest方法并创建相应的Reference对象。我们使用在〖步骤1〗中创建的XMLSignatureFactory实例来创建DigestMethod和Reference对象。
在XMLSignatureFactory中的针对DigestMethod对象的工厂操作如下所示:
public abstract DigestMethod newDigestMethod(String algorithm, DigestMethodParameterSpec params) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException |
【注意】这个params参数用来指定digest算法可能需要的参数;在SHA-1,SHA-256或SHA-512的情况下,我们可以使用null。
为了创建一个Reference对象,XMLSignatureFactory提供了四种操作:
public abstract Reference newReference(String uri, DigestMethod dm); public abstract Reference newReference(String uri, DigestMethod dm, List transforms, String type, String id); public abstract Reference newReference(String uri, DigestMethod dm, List transforms, String type, String id, byte[] digestValue); ...... |
为了全面地理解在那些操作中的输入参数的意思,我们需要分析一下在W3C建议中的Reference元素的XML模式定义:
<element name="Reference" type="ds:ReferenceType"/> <complexType name="ReferenceType"> <sequence> <element ref="ds:Transforms" minOccurs="0"/> <element ref="ds:DigestMethod"/> <element ref="ds:DigestValue"/> </sequence> <attribute name="Id" type="ID" use="optional"/> <attribute name="URI" type="anyURI" use="optional"/> <attribute name="Type" type="anyURI" use="optional"/> </complexType> |
其中,URI属性参考Reference相应的数据对象。
对于我们的示例来说,我们使用SHA-1作为digest方法,并且使用#invoice来在相同的XML签名文档(它包含这个Reference对象的XML描述)中引用一个元素。由#invoice所引用的元素正是我们要在下一步所要讨论的内容。
 
说明:本教程来源互联网或网友上传或出版商,仅为学习研究或媒体推广,wanshiok.com不保证资料的完整性。
2/2 首页 上一页 1 2 |