Search code examples
javaxmlsec

examples or tutorials about santuario (Java)?


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&#13;
J11bH4koqqJQFZPXuKAyuu9eR3W/pZ4EGBMMIVH2aqSOsPMTI5K9l2YOW8fAoEZQtYVWsCrygOyc&#13;
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?


Solution

  • 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

    Reading the input

    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();
    

    Encrypting a document

    To get an encrypted document the following steps were needed:

    1. Generate a secret key
    2. Encrypt that key with the public key
      • optionally add the input key that was used for the encryption
    3. Encrypt the document
      • or any node in the document

    Generate a secret key

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

    Encrypt the key

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

    Encrypt the document

    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);
    
    

    Optionals

    // 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
    }