我来为您介绍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. 最佳实践建议

  1. 安全性考虑

    • 使用强加密算法(AES-256,RSA-2048+)
    • 定期更新加密密钥
    • 使用安全的随机数生成器
  2. 性能优化

    • 对大XML文档使用流式处理
    • 只加密必要的部分
    • 考虑使用对称加密处理大量数据
  3. 依赖管理

    <!-- 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加密功能。

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐