-1

我需要对 XML 进行加密,而 Santuario 看起来是执行此操作的工具。问题是,我不知道如何开始使用它。

从常见问题解答(这似乎真的过时了),我得到了https://svn.apache.org/repos/asf/santuario/xml-security-java/trunk/samples/org/apache/xml/security/samples/,但那是相当空的。

一开始我有一个传入的公钥,我想读取它,所以是这样的:

<?xml version="1.0" encoding="UTF-8"?>
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
  <ds:KeyValue>
    <ds:RSAKeyValue>
      <ds:Modulus>6sNhgtNVksGD4ZK1rW2iiGO11O/BzEIZazovnMK37y3RVvvjmv1z44uA505gyyUTziCntHV9tONm&#13;
J11bH4koqqJQFZPXuKAyuu9eR3W/pZ4EGBMMIVH2aqSOsPMTI5K9l2YOW8fAoEZQtYVWsCrygOyc&#13;
tBiamJZRJ+AKFZCIY5E=</ds:Modulus>
      <ds:Exponent>AQAB</ds:Exponent>
    </ds:RSAKeyValue>
  </ds:KeyValue>
</ds:KeyInfo>

我有点希望将其读入org.apache.xml.security.keys.KeyInfo使用 JAXB,但它没有无操作构造函数,因此无法正常工作。如何解析这样的文档以获取KeyInfo对象?(我试图避免DocumentBuilderFactory等人进行低级处理,但如果需要会这样做)

比我需要使用这个公钥来加密生成的密钥(AES-128),而不是用它来加密 XML 文档。我需要再次将所有这些输出为 XML。我希望lib也有这个工具?

4

1 回答 1

2

可能是这样做的更好方法(如果是这样,请告诉我)但这是我想出的。从这个样本中解决了这个问题

读取输入

假设你有一个 InputStream 或 InputSource:

Document document = XMLUtils.read(is);
// specific to my case, lookup the RSA key value node, and from there go to the parents
NodeList keyInfoList = document.getElementsByTagNameNS(XMLSignature.XMLNS, Constants._TAG_RSAKEYVALUE);
assert keyInfoList.getLength() == 1;
DOMStructure domStructure = new DOMStructure(keyInfoList.item(0).getParentNode().getParentNode());
// from here on it's generic again
KeyInfo keyInfo = KeyInfoFactory.getInstance("DOM").unmarshalKeyInfo(domStructure);
KeyValue keyValue = (KeyValue) keyInfo.getContent().get(0);
publicKey = keyValue.getPublicKey();

加密文档

要获取加密文档,需要执行以下步骤:

  1. 生成密钥
  2. 使用公钥加密该密钥
    • 可选地添加用于加密的输入密钥
  3. 加密文档
    • 或文档中的任何节点

生成密钥

KeyGenerator keygen = KeyGenerator.getInstance("AES");
keygen.init(128);
secretKey = keygen.generateKey();

加密密钥

XMLCipher kekCipher = XMLCipher.getInstance(XMLCipher.RSA_OAEP);
kekCipher.init(XMLCipher.WRAP_MODE, publicKey);
EncryptedKey encryptedKey = kekCipher.encryptKey(inputDocument, secretKey);

加密文档

XMLCipher cipher = XMLCipher.getInstance(XMLCipher.AES_128);
cipher.init(XMLCipher.ENCRYPT_MODE, secretKey);

// Create a KeyInfo for the EncryptedData
EncryptedData encryptedData = cipher.getEncryptedData();
org.apache.xml.security.keys.KeyInfo keyInfo = new org.apache.xml.security.keys.KeyInfo(inputDocument);
keyInfo.add(encryptedKey);
encryptedData.setKeyInfo(keyInfo);

Document result = cipher.doFinal(inputDocument, inputDocument);

可选的

// output the result to a stream:
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
    XMLUtils.outputDOM(result, baos, true);
}

// add key info to the encrypted key
org.apache.xml.security.keys.KeyInfo encryptedKeyKeyInfo = new org.apache.xml.security.keys.KeyInfo(document);
  // not sure the following is needed 
encryptedKeyKeyInfo.getElement()
    .setAttributeNS(
        "http://www.w3.org/2000/xmlns/", 
        "xmlns:dsig", 
        "http://www.w3.org/2000/09/xmldsig#");
encryptedKey.setKeyInfo(encryptedKeyKeyInfo);
encryptedKeyKeyInfo.add(publicKey);

// encrypt a specific node rather than the whole document
NodeList nodeList = document.getElementsByTagNameNS(ns, qName.getLocalPart());
// not sure if this'll work for embedded nodes
for (int i = 0, n = nodeList.getLength(); i < n; i++) {
    Element elementToEncrypt = (Element) nodeList.item(i);
    document = cipher.doFinal(document, elementToEncrypt, false); 
    // last parameter says to either encrypt the children of 'elementToEncrypt'
    // or the element itself
}
于 2019-08-02T15:49:33.660 回答