AutoCAD 3DMAX C语言 Pro/E UG JAVA编程 PHP编程 Maya动画 Matlab应用 Android
Photoshop Word Excel flash VB编程 VC编程 Coreldraw SolidWorks A Designer Unity3D
 首页 > JAVA编程

JavaSE 6基于JSR105的XML签名之实践篇

51自学网 2015-09-02 http://www.wanshiok.com

 

  二、 生成一个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不保证资料的完整性。
 

上一篇:与JBuilder2007的第一次亲密接触  下一篇:强强携手 将AJAX带入Eclipse