科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道JavaSE 6基于JSR105的XML签名之实践篇

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

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

我们分析了有关基于JSR-105进行XML签名的基本概念。在本篇中,我们开始分析一个实际的XML签名示例应用程序。

作者:朱先忠编译 来源:天极开发 2007年10月13日

关键字:

  • 评论
  • 分享微博
  • 分享邮件

在本页阅读全文(共6页)

二、 生成一个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所引用的元素正是我们要在下一步所要讨论的内容。
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章