I need to encrypt an XML and Santuario looks to be the tool to do that with. Problem is, I've got no idea how to get started with it.
From the FAQ (which seems to be really outdated), I got https://svn.apache.org/repos/asf/santuario/xml-security-java/trunk/samples/org/apache/xml/security/samples/, but that is rather empty.
At the start I've got an incoming public key, that I want to read, so something like this:
<?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
J11bH4koqqJQFZPXuKAyuu9eR3W/pZ4EGBMMIVH2aqSOsPMTI5K9l2YOW8fAoEZQtYVWsCrygOyc
tBiamJZRJ+AKFZCIY5E=</ds:Modulus>
<ds:Exponent>AQAB</ds:Exponent>
</ds:RSAKeyValue>
</ds:KeyValue>
</ds:KeyInfo>
I was kinda hoping the read this into org.apache.xml.security.keys.KeyInfo
using JAXB, but it has no no-op constructor, so that won't work. How does one parse such a document to get a KeyInfo
object? (I'm trying to avoid DocumentBuilderFactory
et al. to do low level processing, but will do that if needed)
Than I need to use this public key to encrypt a generated secret key (AES-128), which I than use to encrypt an XML document. I need to output all that as XML again. I was hoping the lib has utils for this too?
Might be a better way of doing this (if so, please let me know) but here is what I came up with. Worked this out from this sample
Assuming you've got a InputStream or 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();
To get an encrypted document the following steps were needed:
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
}