DeepSeek Java通过`javax.xml.crypto`包提供XML签名和加密功能
·
我来为您介绍Java中XML加密的实现方式。Java通过javax.xml.crypto包提供XML签名和加密功能。
1. XML加密基础
主要类和接口
// 核心接口和类
import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dom.*;
import javax.xml.crypto.dsig.dom.*;
import javax.xml.crypto.dsig.keyinfo.*;
// XML处理
import javax.xml.parsers.*;
import org.w3c.dom.*;
2. XML签名示例
以下是使用Java XML加密API创建XML签名的完整示例:
import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
import javax.xml.crypto.dsig.keyinfo.X509Data;
import javax.xml.crypto.dsig.spec.*;
import java.io.*;
import java.security.*;
import java.security.cert.X509Certificate;
import java.util.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
public class XMLSignatureExample {
public static void main(String[] args) throws Exception {
// 1. 创建XML文档
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder builder = dbf.newDocumentBuilder();
Document doc = builder.newDocument();
// 创建示例XML
Element root = doc.createElement("PurchaseOrder");
doc.appendChild(root);
Element item = doc.createElement("Item");
item.setTextContent("Laptop");
root.appendChild(item);
Element price = doc.createElement("Price");
price.setTextContent("999.99");
root.appendChild(price);
// 2. 生成密钥对
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair kp = kpg.generateKeyPair();
// 3. 创建签名
signDocument(doc, kp.getPrivate(), kp.getPublic());
// 4. 验证签名
boolean isValid = verifySignature(doc, kp.getPublic());
System.out.println("Signature valid: " + isValid);
}
public static void signDocument(Document doc, PrivateKey privateKey, PublicKey publicKey)
throws Exception {
// 创建XML签名工厂
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
// 创建引用
Reference ref = fac.newReference(
"", // URI - 空表示整个文档
fac.newDigestMethod(DigestMethod.SHA256, null),
Collections.singletonList(
fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)
),
null,
null
);
// 创建签名的信息
SignedInfo si = fac.newSignedInfo(
fac.newCanonicalizationMethod(
CanonicalizationMethod.INCLUSIVE,
(C14NMethodParameterSpec) null
),
fac.newSignatureMethod(SignatureMethod.RSA_SHA256, null),
Collections.singletonList(ref)
);
// 创建KeyInfo
KeyInfoFactory kif = fac.getKeyInfoFactory();
X509Data xd = kif.newX509Data(Collections.singletonList(
"Certificate placeholder" // 实际应使用真实证书
));
KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd));
// 创建DOMSignContext
DOMSignContext dsc = new DOMSignContext(privateKey, doc.getDocumentElement());
// 创建XMLSignature并签名
XMLSignature signature = fac.newXMLSignature(si, ki);
signature.sign(dsc);
}
public static boolean verifySignature(Document doc, PublicKey publicKey)
throws Exception {
// 找到Signature元素
NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
if (nl.getLength() == 0) {
throw new Exception("Cannot find Signature element");
}
// 创建验证上下文
DOMValidateContext valContext = new DOMValidateContext(
publicKey, nl.item(0)
);
// 创建XML签名工厂
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
XMLSignature signature = fac.unmarshalXMLSignature(valContext);
// 验证签名
return signature.validate(valContext);
}
}
3. XML加密示例
以下是使用Apache Santuario库(更常用的XML加密库)的示例:
// 首先添加Maven依赖
/*
<dependency>
<groupId>org.apache.santuario</groupId>
<artifactId>xmlsec</artifactId>
<version>3.0.3</version>
</dependency>
*/
import org.apache.xml.security.Init;
import org.apache.xml.security.encryption.XMLCipher;
import org.apache.xml.security.encryption.EncryptedData;
import org.apache.xml.security.encryption.EncryptedKey;
import org.apache.xml.security.keys.KeyInfo;
import org.apache.xml.security.keys.content.*;
import org.w3c.dom.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.security.*;
public class XMLEncryptionExample {
static {
Init.init();
}
public static void main(String[] args) throws Exception {
// 1. 创建示例XML文档
Document doc = createSampleDocument();
// 2. 生成对称密钥
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256);
Key secretKey = keyGen.generateKey();
// 3. 生成RSA密钥对
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair kp = kpg.generateKeyPair();
// 4. 加密XML
Document encryptedDoc = encryptXML(doc, secretKey, kp.getPublic());
// 5. 解密XML
Document decryptedDoc = decryptXML(encryptedDoc, kp.getPrivate());
// 输出结果
printDocument(decryptedDoc);
}
public static Document createSampleDocument() throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder builder = dbf.newDocumentBuilder();
Document doc = builder.newDocument();
Element root = doc.createElement("ConfidentialData");
doc.appendChild(root);
Element creditCard = doc.createElement("CreditCard");
creditCard.setTextContent("4111-1111-1111-1111");
root.appendChild(creditCard);
Element expiry = doc.createElement("ExpiryDate");
expiry.setTextContent("12/25");
root.appendChild(expiry);
return doc;
}
public static Document encryptXML(Document doc, Key secretKey, PublicKey publicKey)
throws Exception {
// 创建XMLCipher用于加密
XMLCipher keyCipher = XMLCipher.getInstance(XMLCipher.RSA_v1dot5);
keyCipher.init(XMLCipher.WRAP_MODE, publicKey);
// 加密对称密钥
EncryptedKey encryptedKey = keyCipher.encryptKey(doc, secretKey);
// 创建XMLCipher用于数据加密
XMLCipher dataCipher = XMLCipher.getInstance(XMLCipher.AES_256);
dataCipher.init(XMLCipher.ENCRYPT_MODE, secretKey);
// 获取要加密的元素
Element elementToEncrypt = (Element) doc.getElementsByTagName("CreditCard").item(0);
// 加密元素
dataCipher.doFinal(doc, elementToEncrypt, true);
// 添加加密的密钥信息
Element encryptedDataElement =
(Element) doc.getElementsByTagNameNS(
"http://www.w3.org/2001/04/xmlenc#", "EncryptedData").item(0);
if (encryptedDataElement != null) {
dataCipher.getEncryptedData().setKeyInfo(
dataCipher.createElement(encryptedKey)
);
}
return doc;
}
public static Document decryptXML(Document encryptedDoc, PrivateKey privateKey)
throws Exception {
// 找到EncryptedData元素
Element encryptedDataElement =
(Element) encryptedDoc.getElementsByTagNameNS(
"http://www.w3.org/2001/04/xmlenc#", "EncryptedData").item(0);
if (encryptedDataElement == null) {
throw new Exception("No EncryptedData element found");
}
// 创建XMLCipher
XMLCipher cipher = XMLCipher.getInstance();
cipher.init(XMLCipher.DECRYPT_MODE, null);
// 设置KEK(密钥加密密钥)
cipher.setKEK(privateKey);
// 解密
cipher.doFinal(encryptedDoc, encryptedDataElement);
return encryptedDoc;
}
public static void printDocument(Document doc) throws Exception {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(
new DOMSource(doc),
new StreamResult(new OutputStreamWriter(System.out))
);
}
}
4. 现代XML加密工具类
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.*;
import java.io.*;
import java.security.*;
import java.util.Base64;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import org.w3c.dom.*;
public class XMLSecurityUtils {
// XML加密配置
public static class XMLEncryptor {
private final Cipher cipher;
private final String algorithm;
public XMLEncryptor(String algorithm) throws Exception {
this.algorithm = algorithm;
this.cipher = Cipher.getInstance(algorithm);
}
// 加密XML元素内容
public void encryptElementContent(Document doc, String elementName, Key key)
throws Exception {
XPathFactory xpf = XPathFactory.newInstance();
XPath xpath = xpf.newXPath();
NodeList nodes = (NodeList) xpath.evaluate(
"//" + elementName, doc, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) {
Element element = (Element) nodes.item(i);
String originalText = element.getTextContent();
// 加密内容
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedBytes = cipher.doFinal(originalText.getBytes());
String encryptedBase64 = Base64.getEncoder().encodeToString(encryptedBytes);
// 设置加密后的内容
element.setTextContent(encryptedBase64);
// 添加加密属性
element.setAttribute("encrypted", "true");
element.setAttribute("algorithm", algorithm);
}
}
// 解密XML元素内容
public void decryptElementContent(Document doc, String elementName, Key key)
throws Exception {
XPathFactory xpf = XPathFactory.newInstance();
XPath xpath = xpf.newXPath();
NodeList nodes = (NodeList) xpath.evaluate(
"//" + elementName + "[@encrypted='true']",
doc, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) {
Element element = (Element) nodes.item(i);
String encryptedBase64 = element.getTextContent();
// 解密内容
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decryptedBytes = cipher.doFinal(
Base64.getDecoder().decode(encryptedBase64)
);
// 恢复原始内容
element.setTextContent(new String(decryptedBytes));
element.removeAttribute("encrypted");
element.removeAttribute("algorithm");
}
}
}
// 示例使用
public static void main(String[] args) throws Exception {
// 创建示例XML
Document doc = createDocument();
// 生成AES密钥
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128);
SecretKey secretKey = keyGen.generateKey();
// 创建加密器
XMLEncryptor encryptor = new XMLEncryptor("AES/CBC/PKCS5Padding");
// 加密敏感数据
encryptor.encryptElementContent(doc, "password", secretKey);
encryptor.encryptElementContent(doc, "creditCard", secretKey);
// 保存加密后的XML
saveDocument(doc, "encrypted.xml");
// 解密
encryptor.decryptElementContent(doc, "password", secretKey);
encryptor.decryptElementContent(doc, "creditCard", secretKey);
// 保存解密后的XML
saveDocument(doc, "decrypted.xml");
}
private static Document createDocument() throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.newDocument();
Element root = doc.createElement("users");
doc.appendChild(root);
Element user = doc.createElement("user");
root.appendChild(user);
Element name = doc.createElement("name");
name.setTextContent("John Doe");
user.appendChild(name);
Element password = doc.createElement("password");
password.setTextContent("mySecret123");
user.appendChild(password);
Element creditCard = doc.createElement("creditCard");
creditCard.setTextContent("4111111111111111");
user.appendChild(creditCard);
return doc;
}
private static void saveDocument(Document doc, String filename) throws Exception {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
try (FileWriter writer = new FileWriter(filename)) {
transformer.transform(
new DOMSource(doc),
new StreamResult(writer)
);
}
}
}
5. 最佳实践建议
-
安全性考虑:
- 使用强加密算法(AES-256,RSA-2048+)
- 定期更新加密密钥
- 使用安全的随机数生成器
-
性能优化:
- 对大XML文档使用流式处理
- 只加密必要的部分
- 考虑使用对称加密处理大量数据
-
依赖管理:
<!-- Maven依赖 --> <dependencies> <!-- Java自带 --> <!-- 使用JDK内置的javax.xml.crypto --> <!-- Apache Santuario (推荐) --> <dependency> <groupId>org.apache.santuario</groupId> <artifactId>xmlsec</artifactId> <version>3.0.3</version> </dependency> </xml>
这些示例展示了Java中XML加密的不同实现方式。对于生产环境,建议使用成熟的库如Apache Santuario,它提供了更完整和安全的XML加密功能。
更多推荐



所有评论(0)