Java 內置支持 XML 數字簽名標準。下面展示如何生成 DSA 金鑰對,並對 XML 數據(通過 Reference URI 引用)進行規範化、摘要、簽名,輸出包含 KeyInfo 的 Signature 元素。
import java.security.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.keyinfo.*;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import java.util.Collections;
public class XmlDsigExample {
public static void main(String[] args) throws Exception {
// 1. 生成 DSA 金鑰對 (1024 位)
KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
kpg.initialize(1024, new SecureRandom());
KeyPair dsaKeyPair = kpg.generateKeyPair();
// 2. 獲取 XMLSignatureFactory (默認實現)
XMLSignatureFactory sigFactory = XMLSignatureFactory.getInstance("DOM");
// 3. 創建 Reference:指定被簽名數據 (此處為同一文檔中 Id="Body" 的元素)
// DigestMethod: SHA-1
Reference ref = sigFactory.newReference(
"#Body",
sigFactory.newDigestMethod(DigestMethod.SHA1, null)
);
// 4. 創建 SignedInfo:規範化方法、簽名算法、引用列表
// Canonicalization: 包含註釋的排他規範化
SignedInfo signedInfo = sigFactory.newSignedInfo(
sigFactory.newCanonicalizationMethod(
CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS,
(C14NMethodParameterSpec) null
),
sigFactory.newSignatureMethod(SignatureMethod.DSA_SHA1, null),
Collections.singletonList(ref)
);
// 5. 創建 KeyInfo:包含公鑰值
KeyInfoFactory kif = sigFactory.getKeyInfoFactory();
KeyValue kv = kif.newKeyValue(dsaKeyPair.getPublic());
KeyInfo keyInfo = kif.newKeyInfo(Collections.singletonList(kv));
// 6. 創建 XMLSignature 對象
XMLSignature xmlSig = sigFactory.newXMLSignature(signedInfo, keyInfo);
// 7. 簽名:需提供 XML 文檔上下文 (DOMSignContext)
// 假設 document 是已解析的 org.w3c.dom.Document
// DOMSignContext signContext = new DOMSignContext(dsaKeyPair.getPrivate(), document.getDocumentElement());
// xmlSig.sign(signContext);
// 完成後 document 將包含 元素
System.out.println("XMLSignature 對象創建成功,調用 sign() 即可生成簽名。");
}
}
#Body 表示同文檔中 Id="Body" 的元素。也可簽名外部資源 (https://...) 或整個文檔 ("")。INCLUSIVE_WITH_COMMENTS 保留註釋。DSA_SHA1 對應 https://www.w3.org/2000/09/xmldsig#dsa-sha1。現代建議使用 RSA-SHA256 或 ECDSA-SHA256。
// 驗證端代碼片段
DOMValidateContext valContext = new DOMValidateContext(keyValue.getPublicKey(), signatureElement);
boolean valid = xmlSig.validate(valContext);
xmlSig 通過 sign() 寫入 DOM 文檔。