xml文件签名、验签,特别说明:该签名认证方法需要证书,本地测试使用的是keystore.p12,可根据实际情况修改
第一步:创建证书
keytool -genkey -alias myalias -storetype PKCS12 -keyalg RSA -keysize 2048 -sigalg SHA256withRSA -keystore keystore.p12 -validity 365
第二步:xml签名和验签
import lombok.extern.slf4j.Slf4j;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dsig.*;
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.X509Data;
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 java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
/**
* packageName com.utils
* @author
* @version JDK 8
* @className XmlSignUtil
* @date 2024/5/7 0007
* @description
* 创建证书:keytool -genkey -alias myalias -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 365
* 创建证书:keytool -genkey -alias myalias -storetype PKCS12 -keyalg RSA -keysize 2048 -sigalg SHA256withRSA -keystore keystore.p12 -validity 365
*/
@Slf4j
public class XmlSignUtil {
public static void main(String[] args) throws Exception {
XmlSignUtil xmlSignUtil = new XmlSignUtil();
//加载密钥库文件
String pfxFile = System.getProperty("user.dir")+"/distfile/keystore.p12";
//处理前的文件路径
String srcFile = System.getProperty("user.dir")+"/dec-license-monitor-utils/signed.xml";
//处理后的文件路径
String dstFile = System.getProperty("user.dir")+"/dec-license-monitor-utils/dstFile/signed.xml";
xmlSignUtil.sign(pfxFile,"yw@123".toCharArray(),srcFile,dstFile);
//文件路径
// String dstFile = System.getProperty( "user.dir" ) + File.separator + "license.xml";
boolean flag = xmlSignUtil.validateSign(dstFile);
System.out.println(flag);
}
/**
* xml签名
* @param pfxFile 加载密钥库文件路径
* @param password 证书密码
* @param srcFile 处理前的xml文件路径
* @param dstFile 处理后的xml文件路径
* @throws Exception
*/
public static void sign(String pfxFile,char[] password,String srcFile,String dstFile) {
try {
XMLSignatureFactory xmlSignatureFactory = XMLSignatureFactory.getInstance("DOM");
Transform envelopedTransform = xmlSignatureFactory.newTransform(Transform.ENVELOPED , (XMLStructure) null);
DigestMethod sha1DigestMethod = xmlSignatureFactory.newDigestMethod(DigestMethod.SHA1 , null);
//创建reference元素
Reference reference = xmlSignatureFactory.newReference("" ,
sha1DigestMethod ,
Collections.singletonList(envelopedTransform),
null , null);
SignatureMethod rsaSignatureMethod = xmlSignatureFactory.newSignatureMethod(SignatureMethod.RSA_SHA1 , null);
CanonicalizationMethod canonicalizationMethod = xmlSignatureFactory.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE ,
(XMLStructure) null);
//创建SignedInfo元素
SignedInfo signedInfo = xmlSignatureFactory.newSignedInfo(
canonicalizationMethod ,
rsaSignatureMethod,
Collections.singletonList(reference));
//创建密钥对
KeyStore keyStore = KeyStore.getInstance("PKCS12");
File file = new File(pfxFile);
FileInputStream fis = new FileInputStream(file);
keyStore.load(fis, password);
fis.close();
//获取别名
Enumeration enumas = keyStore.aliases();
String alias = null;
while (enumas.hasMoreElements()) {
alias = (String) enumas.nextElement();
}
//准备密钥对
Key key = keyStore.getKey(alias, password);
KeyPair keyPair = null;
if (key instanceof PrivateKey) {
Certificate cert = keyStore.getCertificate(alias);
PublicKey publicKey = cert.getPublicKey();
keyPair = new KeyPair(publicKey, (PrivateKey) key);
}
X509Certificate x509 = (X509Certificate) keyStore.getCertificate(alias);
KeyInfoFactory keyInfoFactory = xmlSignatureFactory.getKeyInfoFactory();
List x509Content = new ArrayList();
x509Content.add(x509);
x509Content.add(x509.getSubjectX500Principal().getName());
X509Data x509Data = keyInfoFactory.newX509Data(x509Content);
KeyInfo keyInfo = keyInfoFactory.newKeyInfo(Collections.singletonList(x509Data));
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
Document document = documentBuilderFactory.newDocumentBuilder().
parse(new FileInputStream(srcFile));
DOMSignContext domSignContext = new DOMSignContext(keyPair.getPrivate() , document.getDocumentElement());
//创建Signature元素
XMLSignature xmlSignature = xmlSignatureFactory.newXMLSignature(signedInfo , keyInfo);
xmlSignature.sign(domSignContext);
//输出处理后的文件
OutputStream outputStream = new FileOutputStream(dstFile);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(new DOMSource(document) , new StreamResult(outputStream));
log.info("XmlSign签名成功!");
} catch (Exception e) {
log.error("XMLsign签名异常:",e.getMessage());
}
}
/**
* 加密后的文件进行验签
* @param dstFile 处理后的xml文件路径
* @return
* @throws Exception
*/
public static boolean validateSign(String dstFile) {
try {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
Document document = documentBuilderFactory.newDocumentBuilder().
parse(new FileInputStream(dstFile));
NodeList nodeList = document.getElementsByTagNameNS(XMLSignature.XMLNS , "Signature");
if(nodeList.getLength() == 0){
throw new Exception("Cannot find Signature element");
}
DOMValidateContext validateContext = new DOMValidateContext(new X509KeySelector() , nodeList.item(0));
XMLSignatureFactory xmlSignatureFactory = XMLSignatureFactory.getInstance("DOM");
XMLSignature xmlSignature = xmlSignatureFactory.unmarshalXMLSignature(validateContext);
boolean result = xmlSignature.validate(validateContext);
log.info("xmlSign验签结果:"+result);
return result;
} catch (Exception e) {
log.error("XmlSign验签失败:",e.getMessage());
}
return false;
}
xml签名的时候,首先需要有一个xml文件,加密时,在xml文件中添加一个加密节点,内容为加密信息,验签时,根据xml内容和加密信息进行比对。
以上方法亲测有效,如果遇到什么问题,欢迎留言。