java xml 签名_【Java密码学】Java SE 6中XML数字签名的实现

package test.xml.signature;importjava.io.File;importjava.io.FileInputStream;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.ObjectOutputStream;importjava.security.Key;importjava.security.KeyFactory;importjava.security.KeyPair;importjava.security.KeyPairGenerator;importjava.security.PrivateKey;importjava.security.PublicKey;importjava.security.spec.EncodedKeySpec;importjava.security.spec.PKCS8EncodedKeySpec;importjava.security.spec.X509EncodedKeySpec;importjava.util.Collections;importjava.util.List;importjavax.xml.crypto.dom.DOMStructure;importjavax.xml.crypto.dsig.CanonicalizationMethod;importjavax.xml.crypto.dsig.DigestMethod;importjavax.xml.crypto.dsig.Reference;importjavax.xml.crypto.dsig.SignatureMethod;importjavax.xml.crypto.dsig.SignedInfo;importjavax.xml.crypto.dsig.Transform;importjavax.xml.crypto.dsig.XMLSignature;importjavax.xml.crypto.dsig.XMLSignatureFactory;importjavax.xml.crypto.dsig.dom.DOMSignContext;importjavax.xml.crypto.dsig.dom.DOMValidateContext;importjavax.xml.crypto.dsig.keyinfo.KeyInfo;importjavax.xml.crypto.dsig.keyinfo.KeyInfoFactory;importjavax.xml.crypto.dsig.keyinfo.KeyValue;importjavax.xml.crypto.dsig.spec.C14NMethodParameterSpec;importjavax.xml.crypto.dsig.spec.TransformParameterSpec;importjavax.xml.parsers.DocumentBuilderFactory;importjavax.xml.transform.Transformer;importjavax.xml.transform.TransformerFactory;importjavax.xml.transform.dom.DOMSource;importjavax.xml.transform.stream.StreamResult;importorg.w3c.dom.Document;importorg.w3c.dom.Node;importorg.w3c.dom.NodeList;public classSignatureXML {public void saveKey(PublicKey publicKey, PrivateKey privateKey) throwsException{

X509EncodedKeySpec ksp= newX509EncodedKeySpec(publicKey.getEncoded());

FileOutputStream fos= new FileOutputStream("C:\\public.key");

fos.write(ksp.getEncoded());

fos.close();

PKCS8EncodedKeySpec pks= newPKCS8EncodedKeySpec(privateKey.getEncoded());

fos= new FileOutputStream("C:\\private.key");

fos.write(pks.getEncoded());

fos.close();

}public Key LoadKeyFromFile(booleanispk, String keyFile) {

Key key= null;

FileInputStream is= null;try{

is= newFileInputStream(keyFile);byte[] buf = new byte[is.available()];

KeyFactory keyFactory= KeyFactory.getInstance("DSA");

is.read(buf);

EncodedKeySpec keySpec;if(ispk) {

keySpec= newPKCS8EncodedKeySpec(buf);

}else{

keySpec= newX509EncodedKeySpec(buf);

}

key= (!ispk ?(Key) keyFactory.generatePublic(keySpec) : (Key) keyFactory.generatePrivate(keySpec));

}catch(Exception e) {

e.printStackTrace();

}finally{try{

is.close();

}catch(IOException iex) {

iex.printStackTrace();

}

}returnkey;

}public void SignatureXMLDocument(String docPath) throwsException {

DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();

dbf.setNamespaceAware(true);

Document doc= dbf.newDocumentBuilder().parse(newFileInputStream(docPath));this.SignatureXMLDocument(doc);

}public void SignatureXMLDocument(Document doc) throwsException {

XMLSignatureFactory fac=XMLSignatureFactory.getInstance();/*创建 元素,引用整个 XML 文档:

*创建 Reference 的时候将 URI 参数指定为 "" 表示对整个 XML 文档进行引用;

*摘要算法指定为 SHA1;这里将转换方式指定为 ENVELOPED ,

*这样在对整个文档进行引用并生成摘要值的时候, 元素不会被计算在内。*/Transform envelopedTransform= fac.newTransform(Transform.ENVELOPED,(TransformParameterSpec) null);

DigestMethod sha1DigMethod= fac.newDigestMethod(DigestMethod.SHA1, null);

Reference refToRootDoc= fac.newReference("", sha1DigMethod,Collections.singletonList(envelopedTransform), null, null);/*创建 元素

*因为最终的数字签名是针对 元素而生成的,所以需要指定该 XML 元素的规范化方法,

* 以确定最终被处理的数据。这里指定为 INCLUSIVE_WITH_COMMENTS ,

* 表示在规范化 XML 内容的时候会将 XML 注释也包含在内。

* 至此,待签名的内容( 元素)已指定好,再只需要签名所使用的密钥就可以创建数字签名了。*/CanonicalizationMethod c14nWithCommentMethod=fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS,(C14NMethodParameterSpec)null);

SignatureMethod dsa_sha1SigMethod= fac.newSignatureMethod(SignatureMethod.DSA_SHA1, null);

SignedInfo signedInfo=fac.newSignedInfo(c14nWithCommentMethod,dsa_sha1SigMethod,Collections.singletonList(refToRootDoc));/*XML 数字签名规范规定了多种在 中指定验证密钥的方式,比如 ,,, 等等。

* 这里使用 XML 数字签名规范规定必须实现的 来指定验证签名所需的公共密钥。

* 在程序中使用 java.security 包生成 DSA 密钥对。*/

//创建密钥对

KeyPairGenerator kpGen = KeyPairGenerator.getInstance("DSA");

kpGen.initialize(512);

KeyPair keyPair=kpGen.generateKeyPair();

PublicKey publicKey=keyPair.getPublic();

PrivateKey privateKey=keyPair.getPrivate();this.saveKey(publicKey, privateKey);//以公钥为参数创建 元素

KeyInfoFactory keyInfoFac =fac.getKeyInfoFactory();

KeyValue keyValue=keyInfoFac.newKeyValue(publicKey);//根据创建好的 元素创建 元素:

KeyInfo keyInfo =keyInfoFac.newKeyInfo(Collections.singletonList(keyValue));/*这里创建的密钥对,其中的公钥已经用于创建 元素并存放在其中,供签名验证使用,而其中的私钥则会在下一步被用于生成签名。*/

//创建 元素

/*前面已经创建好 和 元素,为了生成最终的数字签名,

* 需要根据这两个元素先创建 元素,然后进行签名,

* 创建出 元素。*/XMLSignature signature=fac.newXMLSignature(signedInfo, keyInfo);/*XMLSignature 类中的 sign 方法用于对文档进行签名,在调用 sign 方法之前,

* 还需要创建 DOMSignContext 对象,为方法调用提供上下文信息,

* 包括签名所使用的私钥和最后生成的 元素所在的目标父元素:*/DOMSignContext dsc= newDOMSignContext(privateKey, doc.getDocumentElement());//生成签名

/*sign 方法会生成签名值,并作为元素值创建 元素,然后将整个 元素加入为待签名文档根元素的直接子元素。*/signature.sign(dsc);

TransformerFactory tf=TransformerFactory.newInstance();

Transformer transformer=tf.newTransformer();

DOMSource source=newDOMSource(doc);

transformer.transform(source,newStreamResult(System.out));

StreamResult result= new StreamResult(new File("C:\\old.xml"));

transformer.transform(source,result);

}private void validate(String signedFile) throwsException {//Parse the signed XML document to unmarshal object.

DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();

dbf.setNamespaceAware(true);

Document doc= dbf.newDocumentBuilder().parse(newFileInputStream(signedFile));this.validate(doc);

}private void validate(Document doc) throwsException {//Search the Signature element

NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS,"Signature");if (nl.getLength() == 0) {throw new Exception("Cannot find Signature element");

}

Node signatureNode= nl.item(0);

XMLSignatureFactory fac= XMLSignatureFactory.getInstance("DOM");

XMLSignature signature= fac.unmarshalXMLSignature(newDOMStructure(signatureNode));//Get the public key for signature validation

KeyValue keyValue = (KeyValue) signature.getKeyInfo().getContent().get(0);

PublicKey pubKey=keyValue.getPublicKey();//Create ValidateContext

DOMValidateContext valCtx = newDOMValidateContext(pubKey,signatureNode);//Validate the XMLSignature

boolean coreValidity =signature.validate(valCtx);//Check core validation status

if (coreValidity == false) {

System.err.println("Core validation failed");//Check the signature validation status

boolean sv =signature.getSignatureValue().validate(valCtx);

System.out.println("Signature validation status: " +sv);//check the validation status of each Reference

List refs =signature.getSignedInfo().getReferences();for (int i = 0; i < refs.size(); i++) {

Reference ref=(Reference) refs.get(i);boolean refValid =ref.validate(valCtx);

System.out.println("Reference[" + i + "] validity status: " +refValid);

}

}else{

System.out.println("Signature passed core validation");

}

}public static voidmain(String[] args) {

SignatureXML signatureXML=newSignatureXML();try{//signatureXML.SignatureXMLDocument("C:\\new.xml");

signatureXML.validate("C:\\old.xml");

}catch(Exception e) {

e.printStackTrace();

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值