Author: anil.saldhana(a)jboss.com
Date: 2009-02-04 18:04:06 -0500 (Wed, 04 Feb 2009)
New Revision: 306
Added:
identity-federation/trunk/identity-fed-api/src/main/java/org/jboss/identity/federation/api/util/XMLEncryptionUtil.java
identity-federation/trunk/identity-fed-api/src/test/java/org/jboss/test/identity/federation/api/saml/v2/XMLEncryptionUnitTestCase.java
Log:
JBID-47: xml enc util
Added:
identity-federation/trunk/identity-fed-api/src/main/java/org/jboss/identity/federation/api/util/XMLEncryptionUtil.java
===================================================================
---
identity-federation/trunk/identity-fed-api/src/main/java/org/jboss/identity/federation/api/util/XMLEncryptionUtil.java
(rev 0)
+++
identity-federation/trunk/identity-fed-api/src/main/java/org/jboss/identity/federation/api/util/XMLEncryptionUtil.java 2009-02-04
23:04:06 UTC (rev 306)
@@ -0,0 +1,203 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.identity.federation.api.util;
+
+import java.security.Key;
+import java.security.PrivateKey;
+
+import javax.crypto.SecretKey;
+
+import org.apache.xml.security.encryption.EncryptedData;
+import org.apache.xml.security.encryption.EncryptedKey;
+import org.apache.xml.security.encryption.XMLCipher;
+import org.apache.xml.security.keys.KeyInfo;
+import org.apache.xml.security.utils.EncryptionConstants;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+/**
+ * XML Encryption Util
+ * <b>Note: </b> This utility is currently using Apache XML Security
+ * library API. JSR-106 is not yet final. Until that happens,we
+ * rely on the non-standard API.
+ *
+ * @author Anil.Saldhana(a)redhat.com
+ * @since Feb 4, 2009
+ */
+public class XMLEncryptionUtil
+{
+ public static final String TRIPLEDES =
"http://www.w3.org/2001/04/xmlenc#tripledes-cbc";
+
+ public static final String AES_128 =
"http://www.w3.org/2001/04/xmlenc#aes128-cbc";
+
+ public static final String AES_256 =
"http://www.w3.org/2001/04/xmlenc#aes256-cbc";
+
+ public static final String AES_192 =
"http://www.w3.org/2001/04/xmlenc#aes192-cbc";
+
+ public static final String RSA_v1dot5 =
"http://www.w3.org/2001/04/xmlenc#rsa-1_5";
+
+ public static final String RSA_OAEP =
"http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p";
+
+ public static final String DIFFIE_HELLMAN =
"http://www.w3.org/2001/04/xmlenc#dh";
+
+ public static final String TRIPLEDES_KeyWrap =
"http://www.w3.org/2001/04/xmlenc#kw-tripledes";
+
+ public static final String AES_128_KeyWrap =
"http://www.w3.org/2001/04/xmlenc#kw-aes128";
+
+ public static final String AES_256_KeyWrap =
"http://www.w3.org/2001/04/xmlenc#kw-aes256";
+
+ public static final String AES_192_KeyWrap =
"http://www.w3.org/2001/04/xmlenc#kw-aes192";
+
+ public static final String SHA1 = "http://www.w3.org/2000/09/xmldsig#sha1";
+
+ public static final String SHA256 =
"http://www.w3.org/2001/04/xmlenc#sha256";
+
+ public static final String SHA512 =
"http://www.w3.org/2001/04/xmlenc#sha512";
+
+ public static final String RIPEMD_160 =
"http://www.w3.org/2001/04/xmlenc#ripemd160";
+
+ public static final String XML_DSIG = "http://www.w3.org/2000/09/xmldsig#";
+
+ public static final String N14C_XML =
"http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
+
+ public static final String N14C_XML_WITH_COMMENTS =
"http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments";
+
+ public static final String EXCL_XML_N14C =
"http://www.w3.org/2001/10/xml-exc-c14n#";
+
+ public static final String EXCL_XML_N14C_WITH_COMMENTS =
"http://www.w3.org/2001/10/xml-exc-c14n#WithComments";
+
+ public static final String BASE64_ENCODING =
"http://www.w3.org/2000/09/xmldsig#base64";
+
+ static
+ {
+ //Initialize the XML Security Library
+ org.apache.xml.security.Init.init();
+ }
+
+ /**
+ * <p>
+ * Encrypt the Key to be transported
+ * </p>
+ * <p>
+ * Data is encrypted with a SecretKey. Then the key needs to be
+ * transported to the other end where it is needed for decryption.
+ * For the Key transport, the SecretKey is encrypted with the
+ * recipient's public key. At the receiving end, the receiver
+ * can decrypt the Secret Key using his private key.s
+ * </p>
+ * @param document
+ * @param keyToBeEncrypted Symmetric Key (SecretKey)
+ * @param keyUsedToEncrypt Asymmetric Key (Public Key)
+ * @return
+ * @throws Exception
+ */
+ public static EncryptedKey encryptKey(Document document,
+ Key keyToBeEncrypted, Key keyUsedToEncrypt) throws Exception
+ {
+ XMLCipher keyCipher = null;
+ String keyAlgo = keyUsedToEncrypt.getAlgorithm();
+ if("RSA".equals(keyAlgo))
+ keyCipher = XMLCipher.getInstance(XMLEncryptionUtil.RSA_v1dot5);
+ else
+ keyCipher = XMLCipher.getInstance(XMLEncryptionUtil.TRIPLEDES_KeyWrap);
+
+ keyCipher.init(XMLCipher.WRAP_MODE, keyUsedToEncrypt);
+ return keyCipher.encryptKey(document, keyToBeEncrypted);
+ }
+
+ /**
+ * Encrypt either the entire document or an element within provided by the tag
+ * @param document The Document to encrypt
+ * @param elementTag An element in the document that you want encrypted (or null
indicating entire document)
+ * @param encryptingKey
+ * @param algo
+ * @return document that is encrypted or contains the encrypted element
+ * @throws Exception
+ */
+ public static Document encrypt(Document document, String elementTag,
+ SecretKey encryptingKey, Key publicKey, String algo) throws Exception
+ {
+ XMLCipher xmlCipher = XMLCipher.getInstance(algo);
+ if(xmlCipher == null)
+ throw new IllegalStateException("Cipher is null for algorithm:" +
algo);
+ xmlCipher.init(XMLCipher.ENCRYPT_MODE, encryptingKey);
+
+ if(elementTag != null)
+ {
+ //Lets check if we need an element
+ NodeList nl = document.getElementsByTagName(elementTag);
+ if(nl.getLength() < 1)
+ throw new IllegalArgumentException(elementTag + " was not found in
document");
+
+ Element elementToEncrypt = (Element) nl.item(0);
+ boolean encryptContentsOnly = true;
+ xmlCipher.doFinal(document,
+ elementToEncrypt, encryptContentsOnly);
+ }
+ else
+ {
+ xmlCipher.doFinal(document, document);
+ }
+ EncryptedKey ekey = encryptKey(document, encryptingKey, publicKey);
+
+ EncryptedData encryptedDataElement =
+ xmlCipher.getEncryptedData();
+ KeyInfo keyInfo = new KeyInfo(document);
+ keyInfo.add(ekey);
+ encryptedDataElement.setKeyInfo(keyInfo);
+
+ return document;
+ }
+
+ /**
+ * Decrypt the document given two keys
+ * <p>The SecretKey needs to be obtained out of band or
+ * needs to be obtained from the KeyInfo using the private key.
+ * </p>
+ * @see #encryptKey(Document, Key, Key)
+ *
+ * @param encryptedDocument
+ * @param encryptingKey
+ * @param signingKey
+ * @return
+ * @throws Exception
+ */
+ public static Document decrypt(Document encryptedDocument,
+ SecretKey encryptingKey, PrivateKey signingKey) throws Exception
+ {
+
+ XMLCipher xmlCipher = XMLCipher.getInstance();
+ xmlCipher.init(XMLCipher.DECRYPT_MODE, encryptingKey); //Symmetric Key
+ xmlCipher.setKEK(signingKey); //Asymmetric Key for Key Transport
+
+ //Get the encrypted element
+ String namespaceURI = EncryptionConstants.EncryptionSpecNS;
+ String localName = EncryptionConstants._TAG_ENCRYPTEDDATA;
+
+ NodeList nl = encryptedDocument.getElementsByTagNameNS(namespaceURI, localName);
+ if(nl == null || nl.getLength() < 1)
+ throw new IllegalStateException("Cannot find encrypted element");
+ Element encryptedDataElement = (Element) nl.item(0);
+ return xmlCipher.doFinal(encryptedDocument, encryptedDataElement);
+ }
+}
\ No newline at end of file
Added:
identity-federation/trunk/identity-fed-api/src/test/java/org/jboss/test/identity/federation/api/saml/v2/XMLEncryptionUnitTestCase.java
===================================================================
---
identity-federation/trunk/identity-fed-api/src/test/java/org/jboss/test/identity/federation/api/saml/v2/XMLEncryptionUnitTestCase.java
(rev 0)
+++
identity-federation/trunk/identity-fed-api/src/test/java/org/jboss/test/identity/federation/api/saml/v2/XMLEncryptionUnitTestCase.java 2009-02-04
23:04:06 UTC (rev 306)
@@ -0,0 +1,112 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.test.identity.federation.api.saml.v2;
+
+import java.io.StringReader;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import junit.framework.TestCase;
+
+import org.jboss.identity.federation.api.util.XMLEncryptionUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.InputSource;
+
+/**
+ * Unit Test the XML Encryption Util
+ * @author Anil.Saldhana(a)redhat.com
+ * @since Feb 4, 2009
+ */
+public class XMLEncryptionUnitTestCase extends TestCase
+{
+ private String docString =
"<rootDoc><element><childOfEl/></element></rootDoc>";
+
+ /**
+ * Test the encryption of an entire document using a symmetric key
+ * @throws Exception
+ */
+ public void testEncryptEntireDocumentWithSymmetricKey() throws Exception
+ {
+ Document doc = this.getDocument();
+ KeyPair kp = this.getKeyPair("RSA");
+
+ SecretKey sk = getSecretKey();
+ Document edoc = XMLEncryptionUtil.encrypt(doc, null, sk, kp.getPublic(),
+ XMLEncryptionUtil.AES_128);
+ assertEquals("xenc:EncryptedData", edoc.getFirstChild().getNodeName());
+
+ //XMLSignatureUtil.marshall(edoc, System.out);
+
+ Document rdoc = XMLEncryptionUtil.decrypt(edoc, sk, kp.getPrivate());
+ //XMLSignatureUtil.marshall(rdoc, System.out);
+ String nodeName = rdoc.getFirstChild().getNodeName();
+ assertEquals("rootDoc",nodeName);
+ }
+
+ /**
+ * Test the encryption of an element inside a document using
+ * a symmetric key
+ * @throws Exception
+ */
+ public void testEncryptElementWithSymmetricKey() throws Exception
+ {
+ Document doc = this.getDocument();
+ KeyPair kp = this.getKeyPair("RSA");
+
+ SecretKey sk = getSecretKey();
+ Document edoc = XMLEncryptionUtil.encrypt(doc, "element", sk,
kp.getPublic(),
+ XMLEncryptionUtil.AES_128);
+ Element encEl = (Element) edoc.getElementsByTagName("element").item(0);
+ assertEquals("xenc:EncryptedData", encEl.getFirstChild().getNodeName());
+
+ Document rdoc = XMLEncryptionUtil.decrypt(edoc, sk, kp.getPrivate());
+ String nodeName = rdoc.getFirstChild().getNodeName();
+ assertEquals("rootDoc",nodeName);
+ }
+
+ private KeyPair getKeyPair(String algo) throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance(algo);
+ return kpg.genKeyPair();
+ }
+
+ private Document getDocument() throws Exception
+ {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ return builder.parse(new InputSource(new StringReader(docString)));
+ }
+
+ private SecretKey getSecretKey() throws Exception
+ {
+ KeyGenerator keyGenerator =
+ KeyGenerator.getInstance("AES");
+ keyGenerator.init(128);
+ return keyGenerator.generateKey();
+ }
+}
\ No newline at end of file