【Java密码学】JavaSE6中XML数字签名的实现

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

【Java密码学】JavaSE6中XML数字签名的实现package test.xml.signature;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.EncodedKeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Collections;
import java.util.List;
import javax.xml.crypto.dom.DOMStructure;
import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.crypto.dsig.DigestMethod;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.SignedInfo;
import javax.xml.crypto.dsig.Transform;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
import javax.xml.crypto.dsig.keyinfo.KeyValue;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class SignatureXML {
public void saveKey(PublicKey publicKey, PrivateKey privateKey) throws Exception{
X509EncodedKeySpec ksp = new X509EncodedKeySpec(publicKey.getEncoded());
FileOutputStream fos = new FileOutputStream("C:\\public.key");
fos.write(ksp.getEncoded());
fos.close();
PKCS8EncodedKeySpec pks = new PKCS8EncodedKeySpec(privateKey.getEncoded());
fos = new FileOutputStream("C:\\private.key");
fos.write(pks.getEncoded());
fos.close();
}
 public Key LoadKeyFromFile(boolean ispk, String keyFile) {
Key key = null;
FileInputStream is = null;
try {
is = new FileInputStream(keyFile);
byte[] buf = new byte[is.available()];
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
is.read(buf);
EncodedKeySpec keySpec;
if (ispk) {
keySpec = new PKCS8EncodedKeySpec(buf);
} else {
keySpec = new X509EncodedKeySpec(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();
}
}
return key;
}
public void SignatureXMLDocument(String docPath) throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Document doc = dbf.newDocumentBuilder().parse(new FileInputStream(docPath));
this.SignatureXMLDocument(doc);
}
public void SignatureXMLDocument(Document doc) throws Exception {
XMLSignatureFactory fac = XMLSignatureFactory.getInstance();
/*创建 <Reference> 元素,引⽤整个 XML ⽂档:
*创建 Reference 的时候将 URI 参数指定为 "" 表⽰对整个 XML ⽂档进⾏引⽤;
*摘要算法指定为 SHA1;这⾥将转换⽅式指定为 ENVELOPED ,
*这样在对整个⽂档进⾏引⽤并⽣成摘要值的时候,<Signature> 元素不会被计算在内。

*/
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);
/*创建 <SignedInfo> 元素
*因为最终的数字签名是针对 <SignedInfo> 元素⽽⽣成的,所以需要指定该 XML 元素的规范化⽅法,
* 以确定最终被处理的数据。

这⾥指定为 INCLUSIVE_WITH_COMMENTS ,
* 表⽰在规范化 XML 内容的时候会将 XML 注释也包含在内。

* ⾄此,待签名的内容(<SignedInfo> 元素)已指定好,再只需要签名所使⽤的密钥就可以创建数字签名了。

*/
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 数字签名规范规定了多种在 <KeyInfo> 中指定验证密钥的⽅式,⽐如 <KeyName>,<KeyValue>,<X509Data>,<PGPData> 等等。

* 这⾥使⽤ XML 数字签名规范规定必须实现的 <DSAKeyValue> 来指定验证签名所需的公共密钥。

* 在程序中使⽤ 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);
//以公钥为参数创建 <KeyValue> 元素
KeyInfoFactory keyInfoFac = fac.getKeyInfoFactory();
KeyValue keyValue = keyInfoFac.newKeyValue(publicKey);
//根据创建好的 <KeyValue> 元素创建 <KeyInfo> 元素:
KeyInfo keyInfo = keyInfoFac.newKeyInfo(Collections.singletonList(keyValue));
/*这⾥创建的密钥对,其中的公钥已经⽤于创建 <KeyInfo> 元素并存放在其中,供签名验证使⽤,⽽其中的私钥则会在下⼀步被⽤于⽣成签名。

*/ //创建 <Signature> 元素
/*前⾯已经创建好 <SignedInfo> 和 <KeyInfo> 元素,为了⽣成最终的数字签名,
* 需要根据这两个元素先创建 <Signature> 元素,然后进⾏签名,
* 创建出 <SignatureValue> 元素。

*/
XMLSignature signature = fac.newXMLSignature(signedInfo, keyInfo);
/*XMLSignature 类中的 sign ⽅法⽤于对⽂档进⾏签名,在调⽤ sign ⽅法之前,
* 还需要创建 DOMSignContext 对象,为⽅法调⽤提供上下⽂信息,
* 包括签名所使⽤的私钥和最后⽣成的 <Signature> 元素所在的⽬标⽗元素:*/
DOMSignContext dsc = new DOMSignContext(privateKey, doc.getDocumentElement());
//⽣成签名
/*sign ⽅法会⽣成签名值,并作为元素值创建 <SignatureValue> 元素,然后将整个 <Signature> 元素加⼊为待签名⽂档根元素的直接⼦元素。

*/ signature.sign(dsc);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
DOMSource source=new DOMSource(doc);
transformer.transform(source, new StreamResult(System.out));
StreamResult result = new StreamResult(new File("C:\\old.xml"));
transformer.transform(source,result);
}
private void validate(String signedFile) throws Exception {
//Parse the signed XML document to unmarshal <Signature> object.
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Document doc = dbf.newDocumentBuilder().parse(new FileInputStream(signedFile));
this.validate(doc);
}
private void validate(Document doc) throws Exception {
// 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(new DOMStructure(signatureNode));
// Get the public key for signature validation
KeyValue keyValue = (KeyValue) signature.getKeyInfo().getContent().get(0);
PublicKey pubKey = keyValue.getPublicKey();
// Create ValidateContext
DOMValidateContext valCtx = new DOMValidateContext(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 void main(String[] args) {
SignatureXML signatureXML=new SignatureXML();
try {
// signatureXML.SignatureXMLDocument("C:\\new.xml");
signatureXML.validate("C:\\old.xml");
} catch (Exception e) {
e.printStackTrace();
}
}
}。

相关文档
最新文档