/* * reserved comment block * DO NOT REMOVE OR ALTER! */ /* * Copyright 2003-2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.sun.org.apache.xml.internal.security.encryption; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.IvParameterSpec; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import com.sun.org.apache.xml.internal.security.algorithms.JCEMapper; import com.sun.org.apache.xml.internal.security.algorithms.MessageDigestAlgorithm; import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer; import com.sun.org.apache.xml.internal.security.c14n.InvalidCanonicalizerException; import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; import com.sun.org.apache.xml.internal.security.keys.KeyInfo; import com.sun.org.apache.xml.internal.security.keys.keyresolver.KeyResolverException; import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.EncryptedKeyResolver; import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException; import com.sun.org.apache.xml.internal.security.transforms.InvalidTransformException; import com.sun.org.apache.xml.internal.security.transforms.TransformationException; import com.sun.org.apache.xml.internal.security.utils.Base64; import com.sun.org.apache.xml.internal.security.utils.Constants; import com.sun.org.apache.xml.internal.security.utils.ElementProxy; import com.sun.org.apache.xml.internal.security.utils.EncryptionConstants; import com.sun.org.apache.xml.internal.security.utils.XMLUtils; import com.sun.org.apache.xml.internal.utils.URI; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.DocumentFragment; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * <code>XMLCipher</code> encrypts and decrypts the contents of * <code>Document</code>s, <code>Element</code>s and <code>Element</code> * contents. It was designed to resemble <code>javax.crypto.Cipher</code> in * order to facilitate understanding of its functioning. * * @author Axl Mattheus (Sun Microsystems) * @author Christian Geuer-Pollmann */ public class XMLCipher { private static java.util.logging.Logger logger = java.util.logging.Logger.getLogger(XMLCipher.class.getName()); //J- /** Triple DES EDE (192 bit key) in CBC mode */ public static final String TRIPLEDES = EncryptionConstants.ALGO_ID_BLOCKCIPHER_TRIPLEDES; /** AES 128 Cipher */ public static final String AES_128 = EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128; /** AES 256 Cipher */ public static final String AES_256 = EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256; /** AES 192 Cipher */ public static final String AES_192 = EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES192; /** RSA 1.5 Cipher */ public static final String RSA_v1dot5 = EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSA15; /** RSA OAEP Cipher */ public static final String RSA_OAEP = EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSAOAEP; /** DIFFIE_HELLMAN Cipher */ public static final String DIFFIE_HELLMAN = EncryptionConstants.ALGO_ID_KEYAGREEMENT_DH; /** Triple DES EDE (192 bit key) in CBC mode KEYWRAP*/ public static final String TRIPLEDES_KeyWrap = EncryptionConstants.ALGO_ID_KEYWRAP_TRIPLEDES; /** AES 128 Cipher KeyWrap */ public static final String AES_128_KeyWrap = EncryptionConstants.ALGO_ID_KEYWRAP_AES128; /** AES 256 Cipher KeyWrap */ public static final String AES_256_KeyWrap = EncryptionConstants.ALGO_ID_KEYWRAP_AES256; /** AES 192 Cipher KeyWrap */ public static final String AES_192_KeyWrap = EncryptionConstants.ALGO_ID_KEYWRAP_AES192; /** SHA1 Cipher */ public static final String SHA1 = Constants.ALGO_ID_DIGEST_SHA1; /** SHA256 Cipher */ public static final String SHA256 = MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA256; /** SHA512 Cipher */ public static final String SHA512 = MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA512; /** RIPEMD Cipher */ public static final String RIPEMD_160 = MessageDigestAlgorithm.ALGO_ID_DIGEST_RIPEMD160; /** XML Signature NS */ public static final String XML_DSIG = Constants.SignatureSpecNS; /** N14C_XML */ public static final String N14C_XML = Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS; /** N14C_XML with comments*/ public static final String N14C_XML_WITH_COMMENTS = Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS; /** N14C_XML excluisve */ public static final String EXCL_XML_N14C = Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS; /** N14C_XML exclusive with commetns*/ public static final String EXCL_XML_N14C_WITH_COMMENTS = Canonicalizer.ALGO_ID_C14N_EXCL_WITH_COMMENTS; /** Base64 encoding */ public static final String BASE64_ENCODING = com.sun.org.apache.xml.internal.security.transforms.Transforms.TRANSFORM_BASE64_DECODE; //J+ /** ENCRYPT Mode */ public static final int ENCRYPT_MODE = Cipher.ENCRYPT_MODE; /** DECRYPT Mode */ public static final int DECRYPT_MODE = Cipher.DECRYPT_MODE; /** UNWRAP Mode */ public static final int UNWRAP_MODE = Cipher.UNWRAP_MODE; /** WRAP Mode */ public static final int WRAP_MODE = Cipher.WRAP_MODE; private static final String ENC_ALGORITHMS = TRIPLEDES + "\n" + AES_128 + "\n" + AES_256 + "\n" + AES_192 + "\n" + RSA_v1dot5 + "\n" + RSA_OAEP + "\n" + TRIPLEDES_KeyWrap + "\n" + AES_128_KeyWrap + "\n" + AES_256_KeyWrap + "\n" + AES_192_KeyWrap+ "\n"; /** Cipher created during initialisation that is used for encryption */ private Cipher _contextCipher; /** Mode that the XMLCipher object is operating in */ private int _cipherMode = Integer.MIN_VALUE; /** URI of algorithm that is being used for cryptographic operation */ private String _algorithm = null; /** Cryptographic provider requested by caller */ private String _requestedJCEProvider = null; /** Holds c14n to serialize, if initialized then _always_ use this c14n to serialize */ private Canonicalizer _canon; /** Used for creation of DOM nodes in WRAP and ENCRYPT modes */ private Document _contextDocument; /** Instance of factory used to create XML Encryption objects */ private Factory _factory; /** Internal serializer class for going to/from UTF-8 */ private Serializer _serializer; /** Local copy of user's key */ private Key _key; /** Local copy of the kek (used to decrypt EncryptedKeys during a * DECRYPT_MODE operation */ private Key _kek; // The EncryptedKey being built (part of a WRAP operation) or read // (part of an UNWRAP operation) private EncryptedKey _ek; // The EncryptedData being built (part of a WRAP operation) or read // (part of an UNWRAP operation) private EncryptedData _ed; /** * Creates a new <code>XMLCipher</code>. * * @since 1.0. */ private XMLCipher() { if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Constructing XMLCipher..."); _factory = new Factory(); _serializer = new Serializer(); } /** * Checks to ensure that the supplied algorithm is valid. * * @param algorithm the algorithm to check. * @return true if the algorithm is valid, otherwise false. * @since 1.0. */ private static boolean isValidEncryptionAlgorithm(String algorithm) { boolean result = ( algorithm.equals(TRIPLEDES) || algorithm.equals(AES_128) || algorithm.equals(AES_256) || algorithm.equals(AES_192) || algorithm.equals(RSA_v1dot5) || algorithm.equals(RSA_OAEP) || algorithm.equals(TRIPLEDES_KeyWrap) || algorithm.equals(AES_128_KeyWrap) || algorithm.equals(AES_256_KeyWrap) || algorithm.equals(AES_192_KeyWrap) ); return (result); } /** * Returns an <code>XMLCipher</code> that implements the specified * transformation and operates on the specified context document. * <p> * If the default provider package supplies an implementation of the * requested transformation, an instance of Cipher containing that * implementation is returned. If the transformation is not available in * the default provider package, other provider packages are searched. * <p> * <b>NOTE<sub>1</sub>:</b> The transformation name does not follow the same * pattern as that oulined in the Java Cryptography Extension Reference * Guide but rather that specified by the XML Encryption Syntax and * Processing document. The rational behind this is to make it easier for a * novice at writing Java Encryption software to use the library. * <p> * <b>NOTE<sub>2</sub>:</b> <code>getInstance()</code> does not follow the * same pattern regarding exceptional conditions as that used in * <code>javax.crypto.Cipher</code>. Instead, it only throws an * <code>XMLEncryptionException</code> which wraps an underlying exception. * The stack trace from the exception should be self explanitory. * * @param transformation the name of the transformation, e.g., * <code>XMLCipher.TRIPLEDES</code> which is shorthand for * "http://www.w3.org/2001/04/xmlenc#tripledes-cbc" * @throws XMLEncryptionException * @return the XMLCipher * @see javax.crypto.Cipher#getInstance(java.lang.String) */ public static XMLCipher getInstance(String transformation) throws XMLEncryptionException { // sanity checks if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Getting XMLCipher..."); if (null == transformation) logger.log(java.util.logging.Level.SEVERE, "Transformation unexpectedly null..."); if(!isValidEncryptionAlgorithm(transformation)) logger.log(java.util.logging.Level.WARNING, "Algorithm non-standard, expected one of " + ENC_ALGORITHMS); XMLCipher instance = new XMLCipher(); instance._algorithm = transformation; instance._key = null; instance._kek = null; /* Create a canonicaliser - used when serialising DOM to octets * prior to encryption (and for the reverse) */ try { instance._canon = Canonicalizer.getInstance (Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS); } catch (InvalidCanonicalizerException ice) { throw new XMLEncryptionException("empty", ice); } String jceAlgorithm = JCEMapper.translateURItoJCEID(transformation); try { instance._contextCipher = Cipher.getInstance(jceAlgorithm); if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "cihper.algoritm = " + instance._contextCipher.getAlgorithm()); } catch (NoSuchAlgorithmException nsae) { throw new XMLEncryptionException("empty", nsae); } catch (NoSuchPaddingException nspe) { throw new XMLEncryptionException("empty", nspe); } return (instance); } public static XMLCipher getInstance(String transformation,Cipher cipher) throws XMLEncryptionException { // sanity checks logger.log(java.util.logging.Level.FINE, "Getting XMLCipher..."); if (null == transformation) logger.log(java.util.logging.Level.SEVERE, "Transformation unexpectedly null..."); if(!isValidEncryptionAlgorithm(transformation)) logger.log(java.util.logging.Level.WARNING, "Algorithm non-standard, expected one of " + ENC_ALGORITHMS); XMLCipher instance = new XMLCipher(); instance._algorithm = transformation; instance._key = null; instance._kek = null; /* Create a canonicaliser - used when serialising DOM to octets * prior to encryption (and for the reverse) */ try { instance._canon = Canonicalizer.getInstance (Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS); } catch (InvalidCanonicalizerException ice) { throw new XMLEncryptionException("empty", ice); } String jceAlgorithm = JCEMapper.translateURItoJCEID(transformation); try { instance._contextCipher = cipher; //Cipher.getInstance(jceAlgorithm); logger.log(java.util.logging.Level.FINE, "cihper.algoritm = " + instance._contextCipher.getAlgorithm()); }catch(Exception ex) { throw new XMLEncryptionException("empty", ex); } return (instance); } /** * Returns an <code>XMLCipher</code> that implements the specified * transformation, operates on the specified context document and serializes * the document with the specified canonicalization algorithm before it * encrypts the document. * <p> * * @param transformation the name of the transformation, e.g., * <code>XMLCipher.TRIPLEDES</code> which is * shorthand for * "http://www.w3.org/2001/04/xmlenc#tripledes-cbc" * @param canon the name of the c14n algorithm, if * <code>null</code> use standard serializer * @return * @throws XMLEncryptionException */ public static XMLCipher getInstance(String transformation, String canon) throws XMLEncryptionException { XMLCipher instance = XMLCipher.getInstance(transformation); if (canon != null) { try { instance._canon = Canonicalizer.getInstance(canon); } catch (InvalidCanonicalizerException ice) { throw new XMLEncryptionException("empty", ice); } } return instance; } /** * Returns an <code>XMLCipher</code> that implements the specified * transformation and operates on the specified context document. * * @param transformation the name of the transformation, e.g., * <code>XMLCipher.TRIPLEDES</code> which is shorthand for * "http://www.w3.org/2001/04/xmlenc#tripledes-cbc" * @param provider the JCE provider that supplies the transformation * @return the XMLCipher * @throws XMLEncryptionException */ public static XMLCipher getProviderInstance(String transformation, String provider) throws XMLEncryptionException { // sanity checks if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Getting XMLCipher..."); if (null == transformation) logger.log(java.util.logging.Level.SEVERE, "Transformation unexpectedly null..."); if(null == provider) logger.log(java.util.logging.Level.SEVERE, "Provider unexpectedly null.."); if("" == provider) logger.log(java.util.logging.Level.SEVERE, "Provider's value unexpectedly not specified..."); if(!isValidEncryptionAlgorithm(transformation)) logger.log(java.util.logging.Level.WARNING, "Algorithm non-standard, expected one of " + ENC_ALGORITHMS); XMLCipher instance = new XMLCipher(); instance._algorithm = transformation; instance._requestedJCEProvider = provider; instance._key = null; instance._kek = null; /* Create a canonicaliser - used when serialising DOM to octets * prior to encryption (and for the reverse) */ try { instance._canon = Canonicalizer.getInstance (Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS); } catch (InvalidCanonicalizerException ice) { throw new XMLEncryptionException("empty", ice); } try { String jceAlgorithm = JCEMapper.translateURItoJCEID(transformation); instance._contextCipher = Cipher.getInstance(jceAlgorithm, provider); if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "cipher._algorithm = " + instance._contextCipher.getAlgorithm()); if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "provider.name = " + provider); } catch (NoSuchAlgorithmException nsae) { throw new XMLEncryptionException("empty", nsae); } catch (NoSuchProviderException nspre) { throw new XMLEncryptionException("empty", nspre); } catch (NoSuchPaddingException nspe) { throw new XMLEncryptionException("empty", nspe); } return (instance); } /** * Returns an <code>XMLCipher</code> that implements the specified * transformation, operates on the specified context document and serializes * the document with the specified canonicalization algorithm before it * encrypts the document. * <p> * * @param transformation the name of the transformation, e.g., * <code>XMLCipher.TRIPLEDES</code> which is * shorthand for * "http://www.w3.org/2001/04/xmlenc#tripledes-cbc" * @param provider the JCE provider that supplies the transformation * @param canon the name of the c14n algorithm, if * <code>null</code> use standard serializer * @return * @throws XMLEncryptionException */ public static XMLCipher getProviderInstance( String transformation, String provider, String canon) throws XMLEncryptionException { XMLCipher instance = XMLCipher.getProviderInstance(transformation, provider); if (canon != null) { try { instance._canon = Canonicalizer.getInstance(canon); } catch (InvalidCanonicalizerException ice) { throw new XMLEncryptionException("empty", ice); } } return instance; } /** * Returns an <code>XMLCipher</code> that implements no specific * transformation, and can therefore only be used for decrypt or * unwrap operations where the encryption method is defined in the * <code>EncryptionMethod</code> element. * * @return The XMLCipher * @throws XMLEncryptionException */ public static XMLCipher getInstance() throws XMLEncryptionException { // sanity checks if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Getting XMLCipher for no transformation..."); XMLCipher instance = new XMLCipher(); instance._algorithm = null; instance._requestedJCEProvider = null; instance._key = null; instance._kek = null; instance._contextCipher = null; /* Create a canonicaliser - used when serialising DOM to octets * prior to encryption (and for the reverse) */ try { instance._canon = Canonicalizer.getInstance (Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS); } catch (InvalidCanonicalizerException ice) { throw new XMLEncryptionException("empty", ice); } return (instance); } /** * Returns an <code>XMLCipher</code> that implements no specific * transformation, and can therefore only be used for decrypt or * unwrap operations where the encryption method is defined in the * <code>EncryptionMethod</code> element. * * Allows the caller to specify a provider that will be used for * cryptographic operations. * * @param provider the JCE provider that supplies the cryptographic * needs. * @return the XMLCipher * @throws XMLEncryptionException */ public static XMLCipher getProviderInstance(String provider) throws XMLEncryptionException { // sanity checks if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Getting XMLCipher, provider but no transformation"); if(null == provider) logger.log(java.util.logging.Level.SEVERE, "Provider unexpectedly null.."); if("" == provider) logger.log(java.util.logging.Level.SEVERE, "Provider's value unexpectedly not specified..."); XMLCipher instance = new XMLCipher(); instance._algorithm = null; instance._requestedJCEProvider = provider; instance._key = null; instance._kek = null; instance._contextCipher = null; try { instance._canon = Canonicalizer.getInstance (Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS); } catch (InvalidCanonicalizerException ice) { throw new XMLEncryptionException("empty", ice); } return (instance); } /** * Initializes this cipher with a key. * <p> * The cipher is initialized for one of the following four operations: * encryption, decryption, key wrapping or key unwrapping, depending on the * value of opmode. * * For WRAP and ENCRYPT modes, this also initialises the internal * EncryptedKey or EncryptedData (with a CipherValue) * structure that will be used during the ensuing operations. This * can be obtained (in order to modify KeyInfo elements etc. prior to * finalising the encryption) by calling * {@link #getEncryptedData} or {@link #getEncryptedKey}. * * @param opmode the operation mode of this cipher (this is one of the * following: ENCRYPT_MODE, DECRYPT_MODE, WRAP_MODE or UNWRAP_MODE) * @param key * @see javax.crypto.Cipher#init(int, java.security.Key) * @throws XMLEncryptionException */ public void init(int opmode, Key key) throws XMLEncryptionException { // sanity checks if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Initializing XMLCipher..."); _ek = null; _ed = null; switch (opmode) { case ENCRYPT_MODE : if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "opmode = ENCRYPT_MODE"); _ed = createEncryptedData(CipherData.VALUE_TYPE, "NO VALUE YET"); break; case DECRYPT_MODE : if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "opmode = DECRYPT_MODE"); break; case WRAP_MODE : if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "opmode = WRAP_MODE"); _ek = createEncryptedKey(CipherData.VALUE_TYPE, "NO VALUE YET"); break; case UNWRAP_MODE : if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "opmode = UNWRAP_MODE"); break; default : logger.log(java.util.logging.Level.SEVERE, "Mode unexpectedly invalid"); throw new XMLEncryptionException("Invalid mode in init"); } _cipherMode = opmode; _key = key; } /** * Get the EncryptedData being build * * Returns the EncryptedData being built during an ENCRYPT operation. * This can then be used by applications to add KeyInfo elements and * set other parameters. * * @return The EncryptedData being built */ public EncryptedData getEncryptedData() { // Sanity checks if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Returning EncryptedData"); return _ed; } /** * Get the EncryptedData being build * * Returns the EncryptedData being built during an ENCRYPT operation. * This can then be used by applications to add KeyInfo elements and * set other parameters. * * @return The EncryptedData being built */ public EncryptedKey getEncryptedKey() { // Sanity checks if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Returning EncryptedKey"); return _ek; } /** * Set a Key Encryption Key. * <p> * The Key Encryption Key (KEK) is used for encrypting/decrypting * EncryptedKey elements. By setting this separately, the XMLCipher * class can know whether a key applies to the data part or wrapped key * part of an encrypted object. * * @param kek The key to use for de/encrypting key data */ public void setKEK(Key kek) { _kek = kek; } /** * Martial an EncryptedData * * Takes an EncryptedData object and returns a DOM Element that * represents the appropriate <code>EncryptedData</code> * <p> * <b>Note:</b> This should only be used in cases where the context * document has been passed in via a call to doFinal. * * @param encryptedData EncryptedData object to martial * @return the DOM <code>Element</code> representing the passed in * object */ public Element martial(EncryptedData encryptedData) { return (_factory.toElement (encryptedData)); } /** * Martial an EncryptedKey * * Takes an EncryptedKey object and returns a DOM Element that * represents the appropriate <code>EncryptedKey</code> * * <p> * <b>Note:</b> This should only be used in cases where the context * document has been passed in via a call to doFinal. * * @param encryptedKey EncryptedKey object to martial * @return the DOM <code>Element</code> representing the passed in * object */ public Element martial(EncryptedKey encryptedKey) { return (_factory.toElement (encryptedKey)); } /** * Martial an EncryptedData * * Takes an EncryptedData object and returns a DOM Element that * represents the appropriate <code>EncryptedData</code> * * @param context The document that will own the returned nodes * @param encryptedData EncryptedData object to martial * @return the DOM <code>Element</code> representing the passed in * object */ public Element martial(Document context, EncryptedData encryptedData) { _contextDocument = context; return (_factory.toElement (encryptedData)); } /** * Martial an EncryptedKey * * Takes an EncryptedKey object and returns a DOM Element that * represents the appropriate <code>EncryptedKey</code> * * @param context The document that will own the created nodes * @param encryptedKey EncryptedKey object to martial * @return the DOM <code>Element</code> representing the passed in * object */ public Element martial(Document context, EncryptedKey encryptedKey) { _contextDocument = context; return (_factory.toElement (encryptedKey)); } /** * Encrypts an <code>Element</code> and replaces it with its encrypted * counterpart in the context <code>Document</code>, that is, the * <code>Document</code> specified when one calls * {@link #getInstance(String) getInstance}. * * @param element the <code>Element</code> to encrypt. * @return the context <code>Document</code> with the encrypted * <code>Element</code> having replaced the source <code>Element</code>. * @throws Exception */ private Document encryptElement(Element element) throws Exception{ if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypting element..."); if(null == element) logger.log(java.util.logging.Level.SEVERE, "Element unexpectedly null..."); if(_cipherMode != ENCRYPT_MODE) if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in ENCRYPT_MODE..."); if (_algorithm == null) { throw new XMLEncryptionException("XMLCipher instance without transformation specified"); } encryptData(_contextDocument, element, false); Element encryptedElement = _factory.toElement(_ed); Node sourceParent = element.getParentNode(); sourceParent.replaceChild(encryptedElement, element); return (_contextDocument); } /** * Encrypts a <code>NodeList</code> (the contents of an * <code>Element</code>) and replaces its parent <code>Element</code>'s * content with this the resulting <code>EncryptedType</code> within the * context <code>Document</code>, that is, the <code>Document</code> * specified when one calls * {@link #getInstance(String) getInstance}. * * @param element the <code>NodeList</code> to encrypt. * @return the context <code>Document</code> with the encrypted * <code>NodeList</code> having replaced the content of the source * <code>Element</code>. * @throws Exception */ private Document encryptElementContent(Element element) throws /* XMLEncryption */Exception { if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypting element content..."); if(null == element) logger.log(java.util.logging.Level.SEVERE, "Element unexpectedly null..."); if(_cipherMode != ENCRYPT_MODE) if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in ENCRYPT_MODE..."); if (_algorithm == null) { throw new XMLEncryptionException("XMLCipher instance without transformation specified"); } encryptData(_contextDocument, element, true); Element encryptedElement = _factory.toElement(_ed); removeContent(element); element.appendChild(encryptedElement); return (_contextDocument); } /** * Process a DOM <code>Document</code> node. The processing depends on the * initialization parameters of {@link #init(int, Key) init()}. * * @param context the context <code>Document</code>. * @param source the <code>Document</code> to be encrypted or decrypted. * @return the processed <code>Document</code>. * @throws Exception to indicate any exceptional conditions. */ public Document doFinal(Document context, Document source) throws /* XMLEncryption */Exception { if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Processing source document..."); if(null == context) logger.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null..."); if(null == source) logger.log(java.util.logging.Level.SEVERE, "Source document unexpectedly null..."); _contextDocument = context; Document result = null; switch (_cipherMode) { case DECRYPT_MODE: result = decryptElement(source.getDocumentElement()); break; case ENCRYPT_MODE: result = encryptElement(source.getDocumentElement()); break; case UNWRAP_MODE: break; case WRAP_MODE: break; default: throw new XMLEncryptionException( "empty", new IllegalStateException()); } return (result); } /** * Process a DOM <code>Element</code> node. The processing depends on the * initialization parameters of {@link #init(int, Key) init()}. * * @param context the context <code>Document</code>. * @param element the <code>Element</code> to be encrypted. * @return the processed <code>Document</code>. * @throws Exception to indicate any exceptional conditions. */ public Document doFinal(Document context, Element element) throws /* XMLEncryption */Exception { if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Processing source element..."); if(null == context) logger.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null..."); if(null == element) logger.log(java.util.logging.Level.SEVERE, "Source element unexpectedly null..."); _contextDocument = context; Document result = null; switch (_cipherMode) { case DECRYPT_MODE: result = decryptElement(element); break; case ENCRYPT_MODE: result = encryptElement(element); break; case UNWRAP_MODE: break; case WRAP_MODE: break; default: throw new XMLEncryptionException( "empty", new IllegalStateException()); } return (result); } /** * Process the contents of a DOM <code>Element</code> node. The processing * depends on the initialization parameters of * {@link #init(int, Key) init()}. * * @param context the context <code>Document</code>. * @param element the <code>Element</code> which contents is to be * encrypted. * @param content * @return the processed <code>Document</code>. * @throws Exception to indicate any exceptional conditions. */ public Document doFinal(Document context, Element element, boolean content) throws /* XMLEncryption*/ Exception { if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Processing source element..."); if(null == context) logger.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null..."); if(null == element) logger.log(java.util.logging.Level.SEVERE, "Source element unexpectedly null..."); _contextDocument = context; Document result = null; switch (_cipherMode) { case DECRYPT_MODE: if (content) { result = decryptElementContent(element); } else { result = decryptElement(element); } break; case ENCRYPT_MODE: if (content) { result = encryptElementContent(element); } else { result = encryptElement(element); } break; case UNWRAP_MODE: break; case WRAP_MODE: break; default: throw new XMLEncryptionException( "empty", new IllegalStateException()); } return (result); } /** * Returns an <code>EncryptedData</code> interface. Use this operation if * you want to have full control over the contents of the * <code>EncryptedData</code> structure. * * this does not change the source document in any way. * * @param context the context <code>Document</code>. * @param element the <code>Element</code> that will be encrypted. * @return the <code>EncryptedData</code> * @throws Exception */ public EncryptedData encryptData(Document context, Element element) throws /* XMLEncryption */Exception { return encryptData(context, element, false); } /** * Returns an <code>EncryptedData</code> interface. Use this operation if * you want to have full control over the contents of the * <code>EncryptedData</code> structure. * * this does not change the source document in any way. * * @param context the context <code>Document</code>. * @param element the <code>Element</code> that will be encrypted. * @param contentMode <code>true</code> to encrypt element's content only, * <code>false</code> otherwise * @return the <code>EncryptedData</code> * @throws Exception */ public EncryptedData encryptData(Document context, Element element, boolean contentMode) throws /* XMLEncryption */ Exception { if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypting element..."); if (null == context) logger.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null..."); if (null == element) logger.log(java.util.logging.Level.SEVERE, "Element unexpectedly null..."); if (_cipherMode != ENCRYPT_MODE) if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in ENCRYPT_MODE..."); _contextDocument = context; if (_algorithm == null) { throw new XMLEncryptionException("XMLCipher instance without transformation specified"); } String serializedOctets = null; if (contentMode) { NodeList children = element.getChildNodes(); if ((null != children)) { serializedOctets = _serializer.serialize(children); } else { Object exArgs[] = { "Element has no content." }; throw new XMLEncryptionException("empty", exArgs); } } else { serializedOctets = _serializer.serialize(element); } if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Serialized octets:\n" + serializedOctets); byte[] encryptedBytes = null; // Now create the working cipher if none was created already Cipher c; if (_contextCipher == null) { String jceAlgorithm = JCEMapper.translateURItoJCEID(_algorithm); if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "alg = " + jceAlgorithm); try { if (_requestedJCEProvider == null) c = Cipher.getInstance(jceAlgorithm); else c = Cipher.getInstance(jceAlgorithm, _requestedJCEProvider); } catch (NoSuchAlgorithmException nsae) { throw new XMLEncryptionException("empty", nsae); } catch (NoSuchProviderException nspre) { throw new XMLEncryptionException("empty", nspre); } catch (NoSuchPaddingException nspae) { throw new XMLEncryptionException("empty", nspae); } } else { c = _contextCipher; } // Now perform the encryption try { // Should internally generate an IV // todo - allow user to set an IV c.init(_cipherMode, _key); } catch (InvalidKeyException ike) { throw new XMLEncryptionException("empty", ike); } try { encryptedBytes = c.doFinal(serializedOctets.getBytes("UTF-8")); if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Expected cipher.outputSize = " + Integer.toString(c.getOutputSize( serializedOctets.getBytes().length))); if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Actual cipher.outputSize = " + Integer.toString(encryptedBytes.length)); } catch (IllegalStateException ise) { throw new XMLEncryptionException("empty", ise); } catch (IllegalBlockSizeException ibse) { throw new XMLEncryptionException("empty", ibse); } catch (BadPaddingException bpe) { throw new XMLEncryptionException("empty", bpe); } catch (UnsupportedEncodingException uee) { throw new XMLEncryptionException("empty", uee); } // Now build up to a properly XML Encryption encoded octet stream // IvParameterSpec iv; byte[] iv = c.getIV(); byte[] finalEncryptedBytes = new byte[iv.length + encryptedBytes.length]; System.arraycopy(iv, 0, finalEncryptedBytes, 0, iv.length); System.arraycopy(encryptedBytes, 0, finalEncryptedBytes, iv.length, encryptedBytes.length); String base64EncodedEncryptedOctets = Base64.encode(finalEncryptedBytes); if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypted octets:\n" + base64EncodedEncryptedOctets); if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypted octets length = " + base64EncodedEncryptedOctets.length()); try { CipherData cd = _ed.getCipherData(); CipherValue cv = cd.getCipherValue(); // cv.setValue(base64EncodedEncryptedOctets.getBytes()); cv.setValue(base64EncodedEncryptedOctets); if (contentMode) { _ed.setType( new URI(EncryptionConstants.TYPE_CONTENT).toString()); } else { _ed.setType( new URI(EncryptionConstants.TYPE_ELEMENT).toString()); } EncryptionMethod method = _factory.newEncryptionMethod(new URI(_algorithm).toString()); _ed.setEncryptionMethod(method); } catch (URI.MalformedURIException mfue) { throw new XMLEncryptionException("empty", mfue); } return (_ed); } public EncryptedData encryptData(Document context, byte [] serializedOctets, boolean contentMode) throws /* XMLEncryption */ Exception { logger.log(java.util.logging.Level.FINE, "Encrypting element..."); if (null == context) logger.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null..."); if (null == serializedOctets) logger.log(java.util.logging.Level.SEVERE, "Canonicalized Data is unexpectedly null..."); if (_cipherMode != ENCRYPT_MODE) logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in ENCRYPT_MODE..."); _contextDocument = context; if (_algorithm == null) { throw new XMLEncryptionException("XMLCipher instance without transformation specified"); } logger.log(java.util.logging.Level.FINE, "Serialized octets:\n" + serializedOctets); byte[] encryptedBytes = null; // Now create the working cipher if none was created already Cipher c; if (_contextCipher == null) { String jceAlgorithm = JCEMapper.translateURItoJCEID(_algorithm); logger.log(java.util.logging.Level.FINE, "alg = " + jceAlgorithm); try { if (_requestedJCEProvider == null) c = Cipher.getInstance(jceAlgorithm); else c = Cipher.getInstance(jceAlgorithm, _requestedJCEProvider); } catch (NoSuchAlgorithmException nsae) { throw new XMLEncryptionException("empty", nsae); } catch (NoSuchProviderException nspre) { throw new XMLEncryptionException("empty", nspre); } catch (NoSuchPaddingException nspae) { throw new XMLEncryptionException("empty", nspae); } } else { c = _contextCipher; } // Now perform the encryption try { // Should internally generate an IV // todo - allow user to set an IV c.init(_cipherMode, _key); } catch (InvalidKeyException ike) { throw new XMLEncryptionException("empty", ike); } try { encryptedBytes = c.doFinal(serializedOctets); logger.log(java.util.logging.Level.FINE, "Expected cipher.outputSize = " + Integer.toString(c.getOutputSize( serializedOctets.length))); logger.log(java.util.logging.Level.FINE, "Actual cipher.outputSize = " + Integer.toString(encryptedBytes.length)); } catch (IllegalStateException ise) { throw new XMLEncryptionException("empty", ise); } catch (IllegalBlockSizeException ibse) { throw new XMLEncryptionException("empty", ibse); } catch (BadPaddingException bpe) { throw new XMLEncryptionException("empty", bpe); } catch (Exception uee) { throw new XMLEncryptionException("empty", uee); } // Now build up to a properly XML Encryption encoded octet stream // IvParameterSpec iv; byte[] iv = c.getIV(); byte[] finalEncryptedBytes = new byte[iv.length + encryptedBytes.length]; System.arraycopy(iv, 0, finalEncryptedBytes, 0, iv.length); System.arraycopy(encryptedBytes, 0, finalEncryptedBytes, iv.length, encryptedBytes.length); String base64EncodedEncryptedOctets = Base64.encode(finalEncryptedBytes); logger.log(java.util.logging.Level.FINE, "Encrypted octets:\n" + base64EncodedEncryptedOctets); logger.log(java.util.logging.Level.FINE, "Encrypted octets length = " + base64EncodedEncryptedOctets.length()); try { CipherData cd = _ed.getCipherData(); CipherValue cv = cd.getCipherValue(); // cv.setValue(base64EncodedEncryptedOctets.getBytes()); cv.setValue(base64EncodedEncryptedOctets); if (contentMode) { _ed.setType( new URI(EncryptionConstants.TYPE_CONTENT).toString()); } else { _ed.setType( new URI(EncryptionConstants.TYPE_ELEMENT).toString()); } EncryptionMethod method = _factory.newEncryptionMethod(new URI(_algorithm).toString()); _ed.setEncryptionMethod(method); } catch (URI.MalformedURIException mfue) { throw new XMLEncryptionException("empty", mfue); } return (_ed); } /** * Returns an <code>EncryptedData</code> interface. Use this operation if * you want to load an <code>EncryptedData</code> structure from a DOM * structure and manipulate the contents * * @param context the context <code>Document</code>. * @param element the <code>Element</code> that will be loaded * @throws XMLEncryptionException * @return */ public EncryptedData loadEncryptedData(Document context, Element element) throws XMLEncryptionException { if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Loading encrypted element..."); if(null == context) logger.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null..."); if(null == element) logger.log(java.util.logging.Level.SEVERE, "Element unexpectedly null..."); if(_cipherMode != DECRYPT_MODE) logger.log(java.util.logging.Level.SEVERE, "XMLCipher unexpectedly not in DECRYPT_MODE..."); _contextDocument = context; _ed = _factory.newEncryptedData(element); return (_ed); } /** * Returns an <code>EncryptedKey</code> interface. Use this operation if * you want to load an <code>EncryptedKey</code> structure from a DOM * structure and manipulate the contents. * * @param context the context <code>Document</code>. * @param element the <code>Element</code> that will be loaded * @return * @throws XMLEncryptionException */ public EncryptedKey loadEncryptedKey(Document context, Element element) throws XMLEncryptionException { if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Loading encrypted key..."); if(null == context) logger.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null..."); if(null == element) logger.log(java.util.logging.Level.SEVERE, "Element unexpectedly null..."); if(_cipherMode != UNWRAP_MODE && _cipherMode != DECRYPT_MODE) if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in UNWRAP_MODE or DECRYPT_MODE..."); _contextDocument = context; _ek = _factory.newEncryptedKey(element); return (_ek); } /** * Returns an <code>EncryptedKey</code> interface. Use this operation if * you want to load an <code>EncryptedKey</code> structure from a DOM * structure and manipulate the contents. * * Assumes that the context document is the document that owns the element * * @param element the <code>Element</code> that will be loaded * @return * @throws XMLEncryptionException */ public EncryptedKey loadEncryptedKey(Element element) throws XMLEncryptionException { return (loadEncryptedKey(element.getOwnerDocument(), element)); } /** * Encrypts a key to an EncryptedKey structure * * @param doc the Context document that will be used to general DOM * @param key Key to encrypt (will use previously set KEK to * perform encryption * @return * @throws XMLEncryptionException */ public EncryptedKey encryptKey(Document doc, Key key) throws XMLEncryptionException { if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypting key ..."); if(null == key) logger.log(java.util.logging.Level.SEVERE, "Key unexpectedly null..."); if(_cipherMode != WRAP_MODE) if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in WRAP_MODE..."); if (_algorithm == null) { throw new XMLEncryptionException("XMLCipher instance without transformation specified"); } _contextDocument = doc; byte[] encryptedBytes = null; Cipher c; if (_contextCipher == null) { // Now create the working cipher String jceAlgorithm = JCEMapper.translateURItoJCEID(_algorithm); if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "alg = " + jceAlgorithm); try { if (_requestedJCEProvider == null) c = Cipher.getInstance(jceAlgorithm); else c = Cipher.getInstance(jceAlgorithm, _requestedJCEProvider); } catch (NoSuchAlgorithmException nsae) { throw new XMLEncryptionException("empty", nsae); } catch (NoSuchProviderException nspre) { throw new XMLEncryptionException("empty", nspre); } catch (NoSuchPaddingException nspae) { throw new XMLEncryptionException("empty", nspae); } } else { c = _contextCipher; } // Now perform the encryption try { // Should internally generate an IV // todo - allow user to set an IV c.init(Cipher.WRAP_MODE, _key); encryptedBytes = c.wrap(key); } catch (InvalidKeyException ike) { throw new XMLEncryptionException("empty", ike); } catch (IllegalBlockSizeException ibse) { throw new XMLEncryptionException("empty", ibse); } String base64EncodedEncryptedOctets = Base64.encode(encryptedBytes); if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypted key octets:\n" + base64EncodedEncryptedOctets); if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypted key octets length = " + base64EncodedEncryptedOctets.length()); CipherValue cv = _ek.getCipherData().getCipherValue(); cv.setValue(base64EncodedEncryptedOctets); try { EncryptionMethod method = _factory.newEncryptionMethod( new URI(_algorithm).toString()); _ek.setEncryptionMethod(method); } catch (URI.MalformedURIException mfue) { throw new XMLEncryptionException("empty", mfue); } return _ek; } /** * Decrypt a key from a passed in EncryptedKey structure * * @param encryptedKey Previously loaded EncryptedKey that needs * to be decrypted. * @param algorithm Algorithm for the decryption * @return a key corresponding to the give type * @throws XMLEncryptionException */ public Key decryptKey(EncryptedKey encryptedKey, String algorithm) throws XMLEncryptionException { if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Decrypting key from previously loaded EncryptedKey..."); if(_cipherMode != UNWRAP_MODE) if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in UNWRAP_MODE..."); if (algorithm == null) { throw new XMLEncryptionException("Cannot decrypt a key without knowing the algorithm"); } if (_key == null) { if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Trying to find a KEK via key resolvers"); KeyInfo ki = encryptedKey.getKeyInfo(); if (ki != null) { try { _key = ki.getSecretKey(); } catch (Exception e) { } } if (_key == null) { logger.log(java.util.logging.Level.SEVERE, "XMLCipher::decryptKey called without a KEK and cannot resolve"); throw new XMLEncryptionException("Unable to decrypt without a KEK"); } } // Obtain the encrypted octets XMLCipherInput cipherInput = new XMLCipherInput(encryptedKey); byte [] encryptedBytes = cipherInput.getBytes(); String jceKeyAlgorithm = JCEMapper.getJCEKeyAlgorithmFromURI(algorithm); Cipher c; if (_contextCipher == null) { // Now create the working cipher String jceAlgorithm = JCEMapper.translateURItoJCEID( encryptedKey.getEncryptionMethod().getAlgorithm()); if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "JCE Algorithm = " + jceAlgorithm); try { if (_requestedJCEProvider == null) c = Cipher.getInstance(jceAlgorithm); else c = Cipher.getInstance(jceAlgorithm, _requestedJCEProvider); } catch (NoSuchAlgorithmException nsae) { throw new XMLEncryptionException("empty", nsae); } catch (NoSuchProviderException nspre) { throw new XMLEncryptionException("empty", nspre); } catch (NoSuchPaddingException nspae) { throw new XMLEncryptionException("empty", nspae); } } else { c = _contextCipher; } Key ret; try { c.init(Cipher.UNWRAP_MODE, _key); ret = c.unwrap(encryptedBytes, jceKeyAlgorithm, Cipher.SECRET_KEY); } catch (InvalidKeyException ike) { throw new XMLEncryptionException("empty", ike); } catch (NoSuchAlgorithmException nsae) { throw new XMLEncryptionException("empty", nsae); } if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Decryption of key type " + algorithm + " OK"); return ret; } /** * Decrypt a key from a passed in EncryptedKey structure. This version * is used mainly internally, when the cipher already has an * EncryptedData loaded. The algorithm URI will be read from the * EncryptedData * * @param encryptedKey Previously loaded EncryptedKey that needs * to be decrypted. * @return a key corresponding to the give type * @throws XMLEncryptionException */ public Key decryptKey(EncryptedKey encryptedKey) throws XMLEncryptionException { return decryptKey(encryptedKey, _ed.getEncryptionMethod().getAlgorithm()); } /** * Removes the contents of a <code>Node</code>. * * @param node the <code>Node</code> to clear. */ private void removeContent(Node node) { NodeList list = node.getChildNodes(); if (list.getLength() > 0) { Node n = list.item(0); if (null != n) { n.getParentNode().removeChild(n); } removeContent(node); } } /** * Decrypts <code>EncryptedData</code> in a single-part operation. * * @param element the <code>EncryptedData</code> to decrypt. * @return the <code>Node</code> as a result of the decrypt operation. * @throws XMLEncryptionException */ private Document decryptElement(Element element) throws XMLEncryptionException { if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Decrypting element..."); if(_cipherMode != DECRYPT_MODE) logger.log(java.util.logging.Level.SEVERE, "XMLCipher unexpectedly not in DECRYPT_MODE..."); String octets; try { octets = new String(decryptToByteArray(element), "UTF-8"); } catch (UnsupportedEncodingException uee) { throw new XMLEncryptionException("empty", uee); } if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Decrypted octets:\n" + octets); Node sourceParent = element.getParentNode(); DocumentFragment decryptedFragment = _serializer.deserialize(octets, sourceParent); // The de-serialiser returns a fragment whose children we need to // take on. if (sourceParent instanceof Document) { // If this is a content decryption, this may have problems _contextDocument.removeChild(_contextDocument.getDocumentElement()); _contextDocument.appendChild(decryptedFragment); } else { sourceParent.replaceChild(decryptedFragment, element); } return (_contextDocument); } /** * * @param element * @return * @throws XMLEncryptionException */ private Document decryptElementContent(Element element) throws XMLEncryptionException { Element e = (Element) element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_ENCRYPTEDDATA).item(0); if (null == e) { throw new XMLEncryptionException("No EncryptedData child element."); } return (decryptElement(e)); } /** * Decrypt an EncryptedData element to a byte array * * When passed in an EncryptedData node, returns the decryption * as a byte array. * * Does not modify the source document * @param element * @return * @throws XMLEncryptionException */ public byte[] decryptToByteArray(Element element) throws XMLEncryptionException { if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Decrypting to ByteArray..."); if(_cipherMode != DECRYPT_MODE) logger.log(java.util.logging.Level.SEVERE, "XMLCipher unexpectedly not in DECRYPT_MODE..."); EncryptedData encryptedData = _factory.newEncryptedData(element); if (_key == null) { KeyInfo ki = encryptedData.getKeyInfo(); if (ki != null) { try { // Add a EncryptedKey resolver ki.registerInternalKeyResolver( new EncryptedKeyResolver(encryptedData. getEncryptionMethod(). getAlgorithm(), _kek)); _key = ki.getSecretKey(); } catch (KeyResolverException kre) { // We will throw in a second... } } if (_key == null) { logger.log(java.util.logging.Level.SEVERE, "XMLCipher::decryptElement called without a key and unable to resolve"); throw new XMLEncryptionException("encryption.nokey"); } } // Obtain the encrypted octets XMLCipherInput cipherInput = new XMLCipherInput(encryptedData); byte [] encryptedBytes = cipherInput.getBytes(); // Now create the working cipher String jceAlgorithm = JCEMapper.translateURItoJCEID(encryptedData.getEncryptionMethod().getAlgorithm()); Cipher c; try { if (_requestedJCEProvider == null) c = Cipher.getInstance(jceAlgorithm); else c = Cipher.getInstance(jceAlgorithm, _requestedJCEProvider); } catch (NoSuchAlgorithmException nsae) { throw new XMLEncryptionException("empty", nsae); } catch (NoSuchProviderException nspre) { throw new XMLEncryptionException("empty", nspre); } catch (NoSuchPaddingException nspae) { throw new XMLEncryptionException("empty", nspae); } // Calculate the IV length and copy out // For now, we only work with Block ciphers, so this will work. // This should probably be put into the JCE mapper. int ivLen = c.getBlockSize(); byte[] ivBytes = new byte[ivLen]; // You may be able to pass the entire piece in to IvParameterSpec // and it will only take the first x bytes, but no way to be certain // that this will work for every JCE provider, so lets copy the // necessary bytes into a dedicated array. System.arraycopy(encryptedBytes, 0, ivBytes, 0, ivLen); IvParameterSpec iv = new IvParameterSpec(ivBytes); try { c.init(_cipherMode, _key, iv); } catch (InvalidKeyException ike) { throw new XMLEncryptionException("empty", ike); } catch (InvalidAlgorithmParameterException iape) { throw new XMLEncryptionException("empty", iape); } byte[] plainBytes; try { plainBytes = c.doFinal(encryptedBytes, ivLen, encryptedBytes.length - ivLen); } catch (IllegalBlockSizeException ibse) { throw new XMLEncryptionException("empty", ibse); } catch (BadPaddingException bpe) { throw new XMLEncryptionException("empty", bpe); } return (plainBytes); } /* * Expose the interface for creating XML Encryption objects */ /** * Creates an <code>EncryptedData</code> <code>Element</code>. * * The newEncryptedData and newEncryptedKey methods create fairly complete * elements that are immediately useable. All the other create* methods * return bare elements that still need to be built upon. *<p> * An EncryptionMethod will still need to be added however * * @param type Either REFERENCE_TYPE or VALUE_TYPE - defines what kind of * CipherData this EncryptedData will contain. * @param value the Base 64 encoded, encrypted text to wrap in the * <code>EncryptedData</code> or the URI to set in the CipherReference * (usage will depend on the <code>type</code> * @return the <code>EncryptedData</code> <code>Element</code>. * * <!-- * <EncryptedData Id[OPT] Type[OPT] MimeType[OPT] Encoding[OPT]> * <EncryptionMethod/>[OPT] * <ds:KeyInfo>[OPT] * <EncryptedKey/>[OPT] * <AgreementMethod/>[OPT] * <ds:KeyName/>[OPT] * <ds:RetrievalMethod/>[OPT] * <ds:[MUL]/>[OPT] * </ds:KeyInfo> * <CipherData>[MAN] * <CipherValue/> XOR <CipherReference/> * </CipherData> * <EncryptionProperties/>[OPT] * </EncryptedData> * --> * @throws XMLEncryptionException */ public EncryptedData createEncryptedData(int type, String value) throws XMLEncryptionException { EncryptedData result = null; CipherData data = null; switch (type) { case CipherData.REFERENCE_TYPE: CipherReference cipherReference = _factory.newCipherReference( value); data = _factory.newCipherData(type); data.setCipherReference(cipherReference); result = _factory.newEncryptedData(data); break; case CipherData.VALUE_TYPE: CipherValue cipherValue = _factory.newCipherValue(value); data = _factory.newCipherData(type); data.setCipherValue(cipherValue); result = _factory.newEncryptedData(data); } return (result); } /** * Creates an <code>EncryptedKey</code> <code>Element</code>. * * The newEncryptedData and newEncryptedKey methods create fairly complete * elements that are immediately useable. All the other create* methods * return bare elements that still need to be built upon. *<p> * An EncryptionMethod will still need to be added however * * @param type Either REFERENCE_TYPE or VALUE_TYPE - defines what kind of * CipherData this EncryptedData will contain. * @param value the Base 64 encoded, encrypted text to wrap in the * <code>EncryptedKey</code> or the URI to set in the CipherReference * (usage will depend on the <code>type</code> * @return the <code>EncryptedKey</code> <code>Element</code>. * * <!-- * <EncryptedKey Id[OPT] Type[OPT] MimeType[OPT] Encoding[OPT]> * <EncryptionMethod/>[OPT] * <ds:KeyInfo>[OPT] * <EncryptedKey/>[OPT] * <AgreementMethod/>[OPT] * <ds:KeyName/>[OPT] * <ds:RetrievalMethod/>[OPT] * <ds:[MUL]/>[OPT] * </ds:KeyInfo> * <CipherData>[MAN] * <CipherValue/> XOR <CipherReference/> * </CipherData> * <EncryptionProperties/>[OPT] * </EncryptedData> * --> * @throws XMLEncryptionException */ public EncryptedKey createEncryptedKey(int type, String value) throws XMLEncryptionException { EncryptedKey result = null; CipherData data = null; switch (type) { case CipherData.REFERENCE_TYPE: CipherReference cipherReference = _factory.newCipherReference( value); data = _factory.newCipherData(type); data.setCipherReference(cipherReference); result = _factory.newEncryptedKey(data); break; case CipherData.VALUE_TYPE: CipherValue cipherValue = _factory.newCipherValue(value); data = _factory.newCipherData(type); data.setCipherValue(cipherValue); result = _factory.newEncryptedKey(data); } return (result); } /** * Create an AgreementMethod object * * @param algorithm Algorithm of the agreement method * @return */ public AgreementMethod createAgreementMethod(String algorithm) { return (_factory.newAgreementMethod(algorithm)); } /** * Create a CipherData object * * @param type Type of this CipherData (either VALUE_TUPE or * REFERENCE_TYPE) * @return */ public CipherData createCipherData(int type) { return (_factory.newCipherData(type)); } /** * Create a CipherReference object * * @return * @param uri The URI that the reference will refer */ public CipherReference createCipherReference(String uri) { return (_factory.newCipherReference(uri)); } /** * Create a CipherValue element * * @param value The value to set the ciphertext to * @return */ public CipherValue createCipherValue(String value) { return (_factory.newCipherValue(value)); } /** * Create an EncryptedMethod object * * @param algorithm Algorithm for the encryption * @return */ public EncryptionMethod createEncryptionMethod(String algorithm) { return (_factory.newEncryptionMethod(algorithm)); } /** * Create an EncryptedProperties element * @return */ public EncryptionProperties createEncryptionProperties() { return (_factory.newEncryptionProperties()); } /** * Create a new EncryptionProperty element * @return */ public EncryptionProperty createEncryptionProperty() { return (_factory.newEncryptionProperty()); } /** * Create a new ReferenceList object * @return * @param type */ public ReferenceList createReferenceList(int type) { return (_factory.newReferenceList(type)); } /** * Create a new Transforms object * <p> * <b>Note</b>: A context document <i>must</i> have been set * elsewhere (possibly via a call to doFinal). If not, use the * createTransforms(Document) method. * @return */ public Transforms createTransforms() { return (_factory.newTransforms()); } /** * Create a new Transforms object * * Because the handling of Transforms is currently done in the signature * code, the creation of a Transforms object <b>requires</b> a * context document. * * @param doc Document that will own the created Transforms node * @return */ public Transforms createTransforms(Document doc) { return (_factory.newTransforms(doc)); } /** * Converts <code>String</code>s into <code>Node</code>s and visa versa. * <p> * <b>NOTE:</b> For internal use only. * * @author Axl Mattheus */ private class Serializer { /** * Initialize the <code>XMLSerializer</code> with the specified context * <code>Document</code>. * <p/> * Setup OutputFormat in a way that the serialization does <b>not</b> * modifiy the contents, that is it shall not do any pretty printing * and so on. This would destroy the original content before * encryption. If that content was signed before encryption and the * serialization modifies the content the signature verification will * fail. */ Serializer() { } /** * Returns a <code>String</code> representation of the specified * <code>Document</code>. * <p/> * Refer also to comments about setup of format. * * @param document the <code>Document</code> to serialize. * @return the <code>String</code> representation of the serilaized * <code>Document</code>. * @throws Exception */ String serialize(Document document) throws Exception { return canonSerialize(document); } /** * Returns a <code>String</code> representation of the specified * <code>Element</code>. * <p/> * Refer also to comments about setup of format. * * @param element the <code>Element</code> to serialize. * @return the <code>String</code> representation of the serilaized * <code>Element</code>. * @throws Exception */ String serialize(Element element) throws Exception { return canonSerialize(element); } /** * Returns a <code>String</code> representation of the specified * <code>NodeList</code>. * <p/> * This is a special case because the NodeList may represent a * <code>DocumentFragment</code>. A document fragement may be a * non-valid XML document (refer to appropriate description of * W3C) because it my start with a non-element node, e.g. a text * node. * <p/> * The methods first converts the node list into a document fragment. * Special care is taken to not destroy the current document, thus * the method clones the nodes (deep cloning) before it appends * them to the document fragment. * <p/> * Refer also to comments about setup of format. * * @param content the <code>NodeList</code> to serialize. * @return the <code>String</code> representation of the serilaized * <code>NodeList</code>. * @throws Exception */ String serialize(NodeList content) throws Exception { //XMLEncryptionException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); _canon.setWriter(baos); _canon.notReset(); for (int i = 0; i < content.getLength(); i++) { _canon.canonicalizeSubtree(content.item(i)); } baos.close(); return baos.toString("UTF-8"); } /** * Use the Canoncializer to serialize the node * @param node * @return * @throws Exception */ String canonSerialize(Node node) throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); _canon.setWriter(baos); _canon.notReset(); _canon.canonicalizeSubtree(node); baos.close(); return baos.toString("UTF-8"); } /** * @param source * @param ctx * @return * @throws XMLEncryptionException * */ DocumentFragment deserialize(String source, Node ctx) throws XMLEncryptionException { DocumentFragment result; final String tagname = "fragment"; // Create the context to parse the document against StringBuffer sb; sb = new StringBuffer(); sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><"+tagname); // Run through each node up to the document node and find any // xmlns: nodes Node wk = ctx; while (wk != null) { NamedNodeMap atts = wk.getAttributes(); int length; if (atts != null) length = atts.getLength(); else length = 0; for (int i = 0 ; i < length ; ++i) { Node att = atts.item(i); if (att.getNodeName().startsWith("xmlns:") || att.getNodeName().equals("xmlns")) { // Check to see if this node has already been found Node p = ctx; boolean found = false; while (p != wk) { NamedNodeMap tstAtts = p.getAttributes(); if (tstAtts != null && tstAtts.getNamedItem(att.getNodeName()) != null) { found = true; break; } p = p.getParentNode(); } if (found == false) { // This is an attribute node sb.append(" " + att.getNodeName() + "=\"" + att.getNodeValue() + "\""); } } } wk = wk.getParentNode(); } sb.append(">" + source + "</" + tagname + ">"); String fragment = sb.toString(); try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); dbf.setAttribute("http://xml.org/sax/features/namespaces", Boolean.TRUE); DocumentBuilder db = dbf.newDocumentBuilder(); Document d = db.parse( new InputSource(new StringReader(fragment))); Element fragElt = (Element) _contextDocument.importNode( d.getDocumentElement(), true); result = _contextDocument.createDocumentFragment(); Node child = fragElt.getFirstChild(); while (child != null) { fragElt.removeChild(child); result.appendChild(child); child = fragElt.getFirstChild(); } // String outp = serialize(d); } catch (SAXException se) { throw new XMLEncryptionException("empty", se); } catch (ParserConfigurationException pce) { throw new XMLEncryptionException("empty", pce); } catch (IOException ioe) { throw new XMLEncryptionException("empty", ioe); } return (result); } } /** * * @author Axl Mattheus */ private class Factory { /** * @param algorithm * @return * */ AgreementMethod newAgreementMethod(String algorithm) { return (new AgreementMethodImpl(algorithm)); } /** * @param type * @return * */ CipherData newCipherData(int type) { return (new CipherDataImpl(type)); } /** * @param uri * @return * */ CipherReference newCipherReference(String uri) { return (new CipherReferenceImpl(uri)); } /** * @param value * @return * */ CipherValue newCipherValue(String value) { return (new CipherValueImpl(value)); } /** * CipherValue newCipherValue(byte[] value) { return (new CipherValueImpl(value)); } */ /** * @param data * @return * */ EncryptedData newEncryptedData(CipherData data) { return (new EncryptedDataImpl(data)); } /** * @param data * @return * */ EncryptedKey newEncryptedKey(CipherData data) { return (new EncryptedKeyImpl(data)); } /** * @param algorithm * @return * */ EncryptionMethod newEncryptionMethod(String algorithm) { return (new EncryptionMethodImpl(algorithm)); } /** * @return * */ EncryptionProperties newEncryptionProperties() { return (new EncryptionPropertiesImpl()); } /** * @return * */ EncryptionProperty newEncryptionProperty() { return (new EncryptionPropertyImpl()); } /** * @param type * @return * */ ReferenceList newReferenceList(int type) { return (new ReferenceListImpl(type)); } /** * @return * */ Transforms newTransforms() { return (new TransformsImpl()); } /** * @param doc * @return * */ Transforms newTransforms(Document doc) { return (new TransformsImpl(doc)); } /** * @param element * @return * @throws XMLEncryptionException * */ // <element name="AgreementMethod" type="xenc:AgreementMethodType"/> // <complexType name="AgreementMethodType" mixed="true"> // <sequence> // <element name="KA-Nonce" minOccurs="0" type="base64Binary"/> // <!-- <element ref="ds:DigestMethod" minOccurs="0"/> --> // <any namespace="##other" minOccurs="0" maxOccurs="unbounded"/> // <element name="OriginatorKeyInfo" minOccurs="0" type="ds:KeyInfoType"/> // <element name="RecipientKeyInfo" minOccurs="0" type="ds:KeyInfoType"/> // </sequence> // <attribute name="Algorithm" type="anyURI" use="required"/> // </complexType> AgreementMethod newAgreementMethod(Element element) throws XMLEncryptionException { if (null == element) { //complain } String algorithm = element.getAttributeNS(null, EncryptionConstants._ATT_ALGORITHM); AgreementMethod result = newAgreementMethod(algorithm); Element kaNonceElement = (Element) element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_KA_NONCE).item(0); if (null != kaNonceElement) { result.setKANonce(kaNonceElement.getNodeValue().getBytes()); } // TODO: /////////////////////////////////////////////////////////// // Figure out how to make this pesky line work.. // <any namespace="##other" minOccurs="0" maxOccurs="unbounded"/> // TODO: Work out how to handle relative URI Element originatorKeyInfoElement = (Element) element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_ORIGINATORKEYINFO).item(0); if (null != originatorKeyInfoElement) { try { result.setOriginatorKeyInfo( new KeyInfo(originatorKeyInfoElement, null)); } catch (XMLSecurityException xse) { throw new XMLEncryptionException("empty", xse); } } // TODO: Work out how to handle relative URI Element recipientKeyInfoElement = (Element) element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_RECIPIENTKEYINFO).item(0); if (null != recipientKeyInfoElement) { try { result.setRecipientKeyInfo( new KeyInfo(recipientKeyInfoElement, null)); } catch (XMLSecurityException xse) { throw new XMLEncryptionException("empty", xse); } } return (result); } /** * @param element * @return * @throws XMLEncryptionException * */ // <element name='CipherData' type='xenc:CipherDataType'/> // <complexType name='CipherDataType'> // <choice> // <element name='CipherValue' type='base64Binary'/> // <element ref='xenc:CipherReference'/> // </choice> // </complexType> CipherData newCipherData(Element element) throws XMLEncryptionException { if (null == element) { // complain } int type = 0; Element e = null; if (element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_CIPHERVALUE).getLength() > 0) { type = CipherData.VALUE_TYPE; e = (Element) element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_CIPHERVALUE).item(0); } else if (element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_CIPHERREFERENCE).getLength() > 0) { type = CipherData.REFERENCE_TYPE; e = (Element) element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_CIPHERREFERENCE).item(0); } CipherData result = newCipherData(type); if (type == CipherData.VALUE_TYPE) { result.setCipherValue(newCipherValue(e)); } else if (type == CipherData.REFERENCE_TYPE) { result.setCipherReference(newCipherReference(e)); } return (result); } /** * @param element * @return * @throws XMLEncryptionException * */ // <element name='CipherReference' type='xenc:CipherReferenceType'/> // <complexType name='CipherReferenceType'> // <sequence> // <element name='Transforms' type='xenc:TransformsType' minOccurs='0'/> // </sequence> // <attribute name='URI' type='anyURI' use='required'/> // </complexType> CipherReference newCipherReference(Element element) throws XMLEncryptionException { Attr URIAttr = element.getAttributeNodeNS(null, EncryptionConstants._ATT_URI); CipherReference result = new CipherReferenceImpl(URIAttr); // Find any Transforms NodeList transformsElements = element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_TRANSFORMS); Element transformsElement = (Element) transformsElements.item(0); if (transformsElement != null) { if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Creating a DSIG based Transforms element"); try { result.setTransforms(new TransformsImpl(transformsElement)); } catch (XMLSignatureException xse) { throw new XMLEncryptionException("empty", xse); } catch (InvalidTransformException ite) { throw new XMLEncryptionException("empty", ite); } catch (XMLSecurityException xse) { throw new XMLEncryptionException("empty", xse); } } return result; } /** * @param element * @return * */ CipherValue newCipherValue(Element element) { String value = XMLUtils.getFullTextChildrenFromElement(element); CipherValue result = newCipherValue(value); return (result); } /** * @param element * @return * @throws XMLEncryptionException * */ // <complexType name='EncryptedType' abstract='true'> // <sequence> // <element name='EncryptionMethod' type='xenc:EncryptionMethodType' // minOccurs='0'/> // <element ref='ds:KeyInfo' minOccurs='0'/> // <element ref='xenc:CipherData'/> // <element ref='xenc:EncryptionProperties' minOccurs='0'/> // </sequence> // <attribute name='Id' type='ID' use='optional'/> // <attribute name='Type' type='anyURI' use='optional'/> // <attribute name='MimeType' type='string' use='optional'/> // <attribute name='Encoding' type='anyURI' use='optional'/> // </complexType> // <element name='EncryptedData' type='xenc:EncryptedDataType'/> // <complexType name='EncryptedDataType'> // <complexContent> // <extension base='xenc:EncryptedType'/> // </complexContent> // </complexType> EncryptedData newEncryptedData(Element element) throws XMLEncryptionException { EncryptedData result = null; NodeList dataElements = element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_CIPHERDATA); // Need to get the last CipherData found, as earlier ones will // be for elements in the KeyInfo lists Element dataElement = (Element) dataElements.item(dataElements.getLength() - 1); CipherData data = newCipherData(dataElement); result = newEncryptedData(data); try { result.setId(element.getAttributeNS( null, EncryptionConstants._ATT_ID)); result.setType(new URI( element.getAttributeNS( null, EncryptionConstants._ATT_TYPE)).toString()); result.setMimeType(element.getAttributeNS( null, EncryptionConstants._ATT_MIMETYPE)); result.setEncoding(new URI( element.getAttributeNS( null, Constants._ATT_ENCODING)).toString()); } catch (URI.MalformedURIException mfue) { // do nothing } Element encryptionMethodElement = (Element) element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_ENCRYPTIONMETHOD).item(0); if (null != encryptionMethodElement) { result.setEncryptionMethod(newEncryptionMethod( encryptionMethodElement)); } // BFL 16/7/03 - simple implementation // TODO: Work out how to handle relative URI Element keyInfoElement = (Element) element.getElementsByTagNameNS( Constants.SignatureSpecNS, Constants._TAG_KEYINFO).item(0); if (null != keyInfoElement) { try { result.setKeyInfo(new KeyInfo(keyInfoElement, null)); } catch (XMLSecurityException xse) { throw new XMLEncryptionException("Error loading Key Info", xse); } } // TODO: Implement Element encryptionPropertiesElement = (Element) element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_ENCRYPTIONPROPERTIES).item(0); if (null != encryptionPropertiesElement) { result.setEncryptionProperties( newEncryptionProperties(encryptionPropertiesElement)); } return (result); } /** * @param element * @return * @throws XMLEncryptionException * */ // <complexType name='EncryptedType' abstract='true'> // <sequence> // <element name='EncryptionMethod' type='xenc:EncryptionMethodType' // minOccurs='0'/> // <element ref='ds:KeyInfo' minOccurs='0'/> // <element ref='xenc:CipherData'/> // <element ref='xenc:EncryptionProperties' minOccurs='0'/> // </sequence> // <attribute name='Id' type='ID' use='optional'/> // <attribute name='Type' type='anyURI' use='optional'/> // <attribute name='MimeType' type='string' use='optional'/> // <attribute name='Encoding' type='anyURI' use='optional'/> // </complexType> // <element name='EncryptedKey' type='xenc:EncryptedKeyType'/> // <complexType name='EncryptedKeyType'> // <complexContent> // <extension base='xenc:EncryptedType'> // <sequence> // <element ref='xenc:ReferenceList' minOccurs='0'/> // <element name='CarriedKeyName' type='string' minOccurs='0'/> // </sequence> // <attribute name='Recipient' type='string' use='optional'/> // </extension> // </complexContent> // </complexType> EncryptedKey newEncryptedKey(Element element) throws XMLEncryptionException { EncryptedKey result = null; NodeList dataElements = element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_CIPHERDATA); Element dataElement = (Element) dataElements.item(dataElements.getLength() - 1); CipherData data = newCipherData(dataElement); result = newEncryptedKey(data); try { result.setId(element.getAttributeNS( null, EncryptionConstants._ATT_ID)); result.setType(new URI( element.getAttributeNS( null, EncryptionConstants._ATT_TYPE)).toString()); result.setMimeType(element.getAttributeNS( null, EncryptionConstants._ATT_MIMETYPE)); result.setEncoding(new URI( element.getAttributeNS( null, Constants._ATT_ENCODING)).toString()); result.setRecipient(element.getAttributeNS( null, EncryptionConstants._ATT_RECIPIENT)); } catch (URI.MalformedURIException mfue) { // do nothing } Element encryptionMethodElement = (Element) element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_ENCRYPTIONMETHOD).item(0); if (null != encryptionMethodElement) { result.setEncryptionMethod(newEncryptionMethod( encryptionMethodElement)); } Element keyInfoElement = (Element) element.getElementsByTagNameNS( Constants.SignatureSpecNS, Constants._TAG_KEYINFO).item(0); if (null != keyInfoElement) { try { result.setKeyInfo(new KeyInfo(keyInfoElement, null)); } catch (XMLSecurityException xse) { throw new XMLEncryptionException("Error loading Key Info", xse); } } // TODO: Implement Element encryptionPropertiesElement = (Element) element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_ENCRYPTIONPROPERTIES).item(0); if (null != encryptionPropertiesElement) { result.setEncryptionProperties( newEncryptionProperties(encryptionPropertiesElement)); } Element referenceListElement = (Element) element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_REFERENCELIST).item(0); if (null != referenceListElement) { result.setReferenceList(newReferenceList(referenceListElement)); } Element carriedNameElement = (Element) element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_CARRIEDKEYNAME).item(0); if (null != carriedNameElement) { result.setCarriedName(carriedNameElement.getNodeValue()); } return (result); } /** * @param element * @return * */ // <complexType name='EncryptionMethodType' mixed='true'> // <sequence> // <element name='KeySize' minOccurs='0' type='xenc:KeySizeType'/> // <element name='OAEPparams' minOccurs='0' type='base64Binary'/> // <any namespace='##other' minOccurs='0' maxOccurs='unbounded'/> // </sequence> // <attribute name='Algorithm' type='anyURI' use='required'/> // </complexType> EncryptionMethod newEncryptionMethod(Element element) { String algorithm = element.getAttributeNS( null, EncryptionConstants._ATT_ALGORITHM); EncryptionMethod result = newEncryptionMethod(algorithm); Element keySizeElement = (Element) element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_KEYSIZE).item(0); if (null != keySizeElement) { result.setKeySize( Integer.valueOf( keySizeElement.getFirstChild().getNodeValue()).intValue()); } Element oaepParamsElement = (Element) element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_OAEPPARAMS).item(0); if (null != oaepParamsElement) { result.setOAEPparams( oaepParamsElement.getNodeValue().getBytes()); } // TODO: Make this mess work // <any namespace='##other' minOccurs='0' maxOccurs='unbounded'/> return (result); } /** * @param element * @return * */ // <element name='EncryptionProperties' type='xenc:EncryptionPropertiesType'/> // <complexType name='EncryptionPropertiesType'> // <sequence> // <element ref='xenc:EncryptionProperty' maxOccurs='unbounded'/> // </sequence> // <attribute name='Id' type='ID' use='optional'/> // </complexType> EncryptionProperties newEncryptionProperties(Element element) { EncryptionProperties result = newEncryptionProperties(); result.setId(element.getAttributeNS( null, EncryptionConstants._ATT_ID)); NodeList encryptionPropertyList = element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_ENCRYPTIONPROPERTY); for(int i = 0; i < encryptionPropertyList.getLength(); i++) { Node n = encryptionPropertyList.item(i); if (null != n) { result.addEncryptionProperty( newEncryptionProperty((Element) n)); } } return (result); } /** * @param element * @return * */ // <element name='EncryptionProperty' type='xenc:EncryptionPropertyType'/> // <complexType name='EncryptionPropertyType' mixed='true'> // <choice maxOccurs='unbounded'> // <any namespace='##other' processContents='lax'/> // </choice> // <attribute name='Target' type='anyURI' use='optional'/> // <attribute name='Id' type='ID' use='optional'/> // <anyAttribute namespace="http://www.w3.org/XML/1998/namespace"/> // </complexType> EncryptionProperty newEncryptionProperty(Element element) { EncryptionProperty result = newEncryptionProperty(); try { result.setTarget(new URI( element.getAttributeNS( null, EncryptionConstants._ATT_TARGET)).toString()); } catch (URI.MalformedURIException mfue) { // do nothing } result.setId(element.getAttributeNS( null, EncryptionConstants._ATT_ID)); // TODO: Make this lot work... // <anyAttribute namespace="http://www.w3.org/XML/1998/namespace"/> // TODO: Make this work... // <any namespace='##other' processContents='lax'/> return (result); } /** * @param element * @return * */ // <element name='ReferenceList'> // <complexType> // <choice minOccurs='1' maxOccurs='unbounded'> // <element name='DataReference' type='xenc:ReferenceType'/> // <element name='KeyReference' type='xenc:ReferenceType'/> // </choice> // </complexType> // </element> ReferenceList newReferenceList(Element element) { int type = 0; if (null != element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_DATAREFERENCE).item(0)) { type = ReferenceList.DATA_REFERENCE; } else if (null != element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_KEYREFERENCE).item(0)) { type = ReferenceList.KEY_REFERENCE; } else { // complain } ReferenceList result = new ReferenceListImpl(type); NodeList list = null; switch (type) { case ReferenceList.DATA_REFERENCE: list = element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_DATAREFERENCE); for (int i = 0; i < list.getLength() ; i++) { String uri = ((Element) list.item(i)).getAttribute("URI"); result.add(result.newDataReference(uri)); } break; case ReferenceList.KEY_REFERENCE: list = element.getElementsByTagNameNS( EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_KEYREFERENCE); for (int i = 0; i < list.getLength() ; i++) { String uri = ((Element) list.item(i)).getAttribute("URI"); result.add(result.newKeyReference(uri)); } } return (result); } /** * @param element * @return * */ Transforms newTransforms(Element element) { return (null); } /** * @param agreementMethod * @return * */ Element toElement(AgreementMethod agreementMethod) { return ((AgreementMethodImpl) agreementMethod).toElement(); } /** * @param cipherData * @return * */ Element toElement(CipherData cipherData) { return ((CipherDataImpl) cipherData).toElement(); } /** * @param cipherReference * @return * */ Element toElement(CipherReference cipherReference) { return ((CipherReferenceImpl) cipherReference).toElement(); } /** * @param cipherValue * @return * */ Element toElement(CipherValue cipherValue) { return ((CipherValueImpl) cipherValue).toElement(); } /** * @param encryptedData * @return * */ Element toElement(EncryptedData encryptedData) { return ((EncryptedDataImpl) encryptedData).toElement(); } /** * @param encryptedKey * @return * */ Element toElement(EncryptedKey encryptedKey) { return ((EncryptedKeyImpl) encryptedKey).toElement(); } /** * @param encryptionMethod * @return * */ Element toElement(EncryptionMethod encryptionMethod) { return ((EncryptionMethodImpl) encryptionMethod).toElement(); } /** * @param encryptionProperties * @return * */ Element toElement(EncryptionProperties encryptionProperties) { return ((EncryptionPropertiesImpl) encryptionProperties).toElement(); } /** * @param encryptionProperty * @return * */ Element toElement(EncryptionProperty encryptionProperty) { return ((EncryptionPropertyImpl) encryptionProperty).toElement(); } Element toElement(ReferenceList referenceList) { return ((ReferenceListImpl) referenceList).toElement(); } /** * @param transforms * @return * */ Element toElement(Transforms transforms) { return ((TransformsImpl) transforms).toElement(); } // <element name="AgreementMethod" type="xenc:AgreementMethodType"/> // <complexType name="AgreementMethodType" mixed="true"> // <sequence> // <element name="KA-Nonce" minOccurs="0" type="base64Binary"/> // <!-- <element ref="ds:DigestMethod" minOccurs="0"/> --> // <any namespace="##other" minOccurs="0" maxOccurs="unbounded"/> // <element name="OriginatorKeyInfo" minOccurs="0" type="ds:KeyInfoType"/> // <element name="RecipientKeyInfo" minOccurs="0" type="ds:KeyInfoType"/> // </sequence> // <attribute name="Algorithm" type="anyURI" use="required"/> // </complexType> private class AgreementMethodImpl implements AgreementMethod { private byte[] kaNonce = null; private List agreementMethodInformation = null; private KeyInfo originatorKeyInfo = null; private KeyInfo recipientKeyInfo = null; private String algorithmURI = null; /** * @param algorithm */ public AgreementMethodImpl(String algorithm) { agreementMethodInformation = new LinkedList(); URI tmpAlgorithm = null; try { tmpAlgorithm = new URI(algorithm); } catch (URI.MalformedURIException fmue) { //complain? } algorithmURI = tmpAlgorithm.toString(); } /** @inheritDoc */ public byte[] getKANonce() { return (kaNonce); } /** @inheritDoc */ public void setKANonce(byte[] kanonce) { kaNonce = kanonce; } /** @inheritDoc */ public Iterator getAgreementMethodInformation() { return (agreementMethodInformation.iterator()); } /** @inheritDoc */ public void addAgreementMethodInformation(Element info) { agreementMethodInformation.add(info); } /** @inheritDoc */ public void revoveAgreementMethodInformation(Element info) { agreementMethodInformation.remove(info); } /** @inheritDoc */ public KeyInfo getOriginatorKeyInfo() { return (originatorKeyInfo); } /** @inheritDoc */ public void setOriginatorKeyInfo(KeyInfo keyInfo) { originatorKeyInfo = keyInfo; } /** @inheritDoc */ public KeyInfo getRecipientKeyInfo() { return (recipientKeyInfo); } /** @inheritDoc */ public void setRecipientKeyInfo(KeyInfo keyInfo) { recipientKeyInfo = keyInfo; } /** @inheritDoc */ public String getAlgorithm() { return (algorithmURI); } /** @param algorithm*/ public void setAlgorithm(String algorithm) { URI tmpAlgorithm = null; try { tmpAlgorithm = new URI(algorithm); } catch (URI.MalformedURIException mfue) { //complain } algorithm = tmpAlgorithm.toString(); } // <element name="AgreementMethod" type="xenc:AgreementMethodType"/> // <complexType name="AgreementMethodType" mixed="true"> // <sequence> // <element name="KA-Nonce" minOccurs="0" type="base64Binary"/> // <!-- <element ref="ds:DigestMethod" minOccurs="0"/> --> // <any namespace="##other" minOccurs="0" maxOccurs="unbounded"/> // <element name="OriginatorKeyInfo" minOccurs="0" type="ds:KeyInfoType"/> // <element name="RecipientKeyInfo" minOccurs="0" type="ds:KeyInfoType"/> // </sequence> // <attribute name="Algorithm" type="anyURI" use="required"/> // </complexType> Element toElement() { Element result = ElementProxy.createElementForFamily( _contextDocument, EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_AGREEMENTMETHOD); result.setAttributeNS( null, EncryptionConstants._ATT_ALGORITHM, algorithmURI); if (null != kaNonce) { result.appendChild( ElementProxy.createElementForFamily( _contextDocument, EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_KA_NONCE)).appendChild( _contextDocument.createTextNode(new String(kaNonce))); } if (!agreementMethodInformation.isEmpty()) { Iterator itr = agreementMethodInformation.iterator(); while (itr.hasNext()) { result.appendChild((Element) itr.next()); } } if (null != originatorKeyInfo) { result.appendChild(originatorKeyInfo.getElement()); } if (null != recipientKeyInfo) { result.appendChild(recipientKeyInfo.getElement()); } return (result); } } // <element name='CipherData' type='xenc:CipherDataType'/> // <complexType name='CipherDataType'> // <choice> // <element name='CipherValue' type='base64Binary'/> // <element ref='xenc:CipherReference'/> // </choice> // </complexType> private class CipherDataImpl implements CipherData { private static final String valueMessage = "Data type is reference type."; private static final String referenceMessage = "Data type is value type."; private CipherValue cipherValue = null; private CipherReference cipherReference = null; private int cipherType = Integer.MIN_VALUE; /** * @param type */ public CipherDataImpl(int type) { cipherType = type; } /** @inheritDoc */ public CipherValue getCipherValue() { return (cipherValue); } /** @inheritDoc */ public void setCipherValue(CipherValue value) throws XMLEncryptionException { if (cipherType == REFERENCE_TYPE) { throw new XMLEncryptionException("empty", new UnsupportedOperationException(valueMessage)); } cipherValue = value; } /** @inheritDoc */ public CipherReference getCipherReference() { return (cipherReference); } /** @inheritDoc */ public void setCipherReference(CipherReference reference) throws XMLEncryptionException { if (cipherType == VALUE_TYPE) { throw new XMLEncryptionException("empty", new UnsupportedOperationException(referenceMessage)); } cipherReference = reference; } /** @inheritDoc */ public int getDataType() { return (cipherType); } // <element name='CipherData' type='xenc:CipherDataType'/> // <complexType name='CipherDataType'> // <choice> // <element name='CipherValue' type='base64Binary'/> // <element ref='xenc:CipherReference'/> // </choice> // </complexType> Element toElement() { Element result = ElementProxy.createElementForFamily( _contextDocument, EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_CIPHERDATA); if (cipherType == VALUE_TYPE) { result.appendChild( ((CipherValueImpl) cipherValue).toElement()); } else if (cipherType == REFERENCE_TYPE) { result.appendChild( ((CipherReferenceImpl) cipherReference).toElement()); } else { // complain } return (result); } } // <element name='CipherReference' type='xenc:CipherReferenceType'/> // <complexType name='CipherReferenceType'> // <sequence> // <element name='Transforms' type='xenc:TransformsType' minOccurs='0'/> // </sequence> // <attribute name='URI' type='anyURI' use='required'/> // </complexType> private class CipherReferenceImpl implements CipherReference { private String referenceURI = null; private Transforms referenceTransforms = null; private Attr referenceNode = null; /** * @param uri */ public CipherReferenceImpl(String uri) { /* Don't check validity of URI as may be "" */ referenceURI = uri; referenceNode = null; } /** * @param uri */ public CipherReferenceImpl(Attr uri) { referenceURI = uri.getNodeValue(); referenceNode = uri; } /** @inheritDoc */ public String getURI() { return (referenceURI); } /** @inheritDoc */ public Attr getURIAsAttr() { return (referenceNode); } /** @inheritDoc */ public Transforms getTransforms() { return (referenceTransforms); } /** @inheritDoc */ public void setTransforms(Transforms transforms) { referenceTransforms = transforms; } // <element name='CipherReference' type='xenc:CipherReferenceType'/> // <complexType name='CipherReferenceType'> // <sequence> // <element name='Transforms' type='xenc:TransformsType' minOccurs='0'/> // </sequence> // <attribute name='URI' type='anyURI' use='required'/> // </complexType> Element toElement() { Element result = ElementProxy.createElementForFamily( _contextDocument, EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_CIPHERREFERENCE); result.setAttributeNS( null, EncryptionConstants._ATT_URI, referenceURI); if (null != referenceTransforms) { result.appendChild( ((TransformsImpl) referenceTransforms).toElement()); } return (result); } } private class CipherValueImpl implements CipherValue { private String cipherValue = null; // public CipherValueImpl(byte[] value) { // cipherValue = value; // } /** * @param value */ public CipherValueImpl(String value) { // cipherValue = value.getBytes(); cipherValue = value; } /** @inheritDoc */ public String getValue() { return (cipherValue); } // public void setValue(byte[] value) { // public void setValue(String value) { // cipherValue = value; // } /** @inheritDoc */ public void setValue(String value) { // cipherValue = value.getBytes(); cipherValue = value; } Element toElement() { Element result = ElementProxy.createElementForFamily( _contextDocument, EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_CIPHERVALUE); result.appendChild(_contextDocument.createTextNode( new String(cipherValue))); return (result); } } // <complexType name='EncryptedType' abstract='true'> // <sequence> // <element name='EncryptionMethod' type='xenc:EncryptionMethodType' // minOccurs='0'/> // <element ref='ds:KeyInfo' minOccurs='0'/> // <element ref='xenc:CipherData'/> // <element ref='xenc:EncryptionProperties' minOccurs='0'/> // </sequence> // <attribute name='Id' type='ID' use='optional'/> // <attribute name='Type' type='anyURI' use='optional'/> // <attribute name='MimeType' type='string' use='optional'/> // <attribute name='Encoding' type='anyURI' use='optional'/> // </complexType> // <element name='EncryptedData' type='xenc:EncryptedDataType'/> // <complexType name='EncryptedDataType'> // <complexContent> // <extension base='xenc:EncryptedType'/> // </complexContent> // </complexType> private class EncryptedDataImpl extends EncryptedTypeImpl implements EncryptedData { /** * @param data */ public EncryptedDataImpl(CipherData data) { super(data); } // <complexType name='EncryptedType' abstract='true'> // <sequence> // <element name='EncryptionMethod' type='xenc:EncryptionMethodType' // minOccurs='0'/> // <element ref='ds:KeyInfo' minOccurs='0'/> // <element ref='xenc:CipherData'/> // <element ref='xenc:EncryptionProperties' minOccurs='0'/> // </sequence> // <attribute name='Id' type='ID' use='optional'/> // <attribute name='Type' type='anyURI' use='optional'/> // <attribute name='MimeType' type='string' use='optional'/> // <attribute name='Encoding' type='anyURI' use='optional'/> // </complexType> // <element name='EncryptedData' type='xenc:EncryptedDataType'/> // <complexType name='EncryptedDataType'> // <complexContent> // <extension base='xenc:EncryptedType'/> // </complexContent> // </complexType> Element toElement() { Element result = ElementProxy.createElementForFamily( _contextDocument, EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_ENCRYPTEDDATA); if (null != super.getId()) { result.setAttributeNS( null, EncryptionConstants._ATT_ID, super.getId()); } if (null != super.getType()) { result.setAttributeNS( null, EncryptionConstants._ATT_TYPE, super.getType().toString()); } if (null != super.getMimeType()) { result.setAttributeNS( null, EncryptionConstants._ATT_MIMETYPE, super.getMimeType()); } if (null != super.getEncoding()) { result.setAttributeNS( null, EncryptionConstants._ATT_ENCODING, super.getEncoding().toString()); } if (null != super.getEncryptionMethod()) { result.appendChild(((EncryptionMethodImpl) super.getEncryptionMethod()).toElement()); } if (null != super.getKeyInfo()) { result.appendChild(super.getKeyInfo().getElement()); } result.appendChild( ((CipherDataImpl) super.getCipherData()).toElement()); if (null != super.getEncryptionProperties()) { result.appendChild(((EncryptionPropertiesImpl) super.getEncryptionProperties()).toElement()); } return (result); } } // <complexType name='EncryptedType' abstract='true'> // <sequence> // <element name='EncryptionMethod' type='xenc:EncryptionMethodType' // minOccurs='0'/> // <element ref='ds:KeyInfo' minOccurs='0'/> // <element ref='xenc:CipherData'/> // <element ref='xenc:EncryptionProperties' minOccurs='0'/> // </sequence> // <attribute name='Id' type='ID' use='optional'/> // <attribute name='Type' type='anyURI' use='optional'/> // <attribute name='MimeType' type='string' use='optional'/> // <attribute name='Encoding' type='anyURI' use='optional'/> // </complexType> // <element name='EncryptedKey' type='xenc:EncryptedKeyType'/> // <complexType name='EncryptedKeyType'> // <complexContent> // <extension base='xenc:EncryptedType'> // <sequence> // <element ref='xenc:ReferenceList' minOccurs='0'/> // <element name='CarriedKeyName' type='string' minOccurs='0'/> // </sequence> // <attribute name='Recipient' type='string' use='optional'/> // </extension> // </complexContent> // </complexType> private class EncryptedKeyImpl extends EncryptedTypeImpl implements EncryptedKey { private String keyRecipient = null; private ReferenceList referenceList = null; private String carriedName = null; /** * @param data */ public EncryptedKeyImpl(CipherData data) { super(data); } /** @inheritDoc */ public String getRecipient() { return (keyRecipient); } /** @inheritDoc */ public void setRecipient(String recipient) { keyRecipient = recipient; } /** @inheritDoc */ public ReferenceList getReferenceList() { return (referenceList); } /** @inheritDoc */ public void setReferenceList(ReferenceList list) { referenceList = list; } /** @inheritDoc */ public String getCarriedName() { return (carriedName); } /** @inheritDoc */ public void setCarriedName(String name) { carriedName = name; } // <complexType name='EncryptedType' abstract='true'> // <sequence> // <element name='EncryptionMethod' type='xenc:EncryptionMethodType' // minOccurs='0'/> // <element ref='ds:KeyInfo' minOccurs='0'/> // <element ref='xenc:CipherData'/> // <element ref='xenc:EncryptionProperties' minOccurs='0'/> // </sequence> // <attribute name='Id' type='ID' use='optional'/> // <attribute name='Type' type='anyURI' use='optional'/> // <attribute name='MimeType' type='string' use='optional'/> // <attribute name='Encoding' type='anyURI' use='optional'/> // </complexType> // <element name='EncryptedKey' type='xenc:EncryptedKeyType'/> // <complexType name='EncryptedKeyType'> // <complexContent> // <extension base='xenc:EncryptedType'> // <sequence> // <element ref='xenc:ReferenceList' minOccurs='0'/> // <element name='CarriedKeyName' type='string' minOccurs='0'/> // </sequence> // <attribute name='Recipient' type='string' use='optional'/> // </extension> // </complexContent> // </complexType> Element toElement() { Element result = ElementProxy.createElementForFamily( _contextDocument, EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_ENCRYPTEDKEY); if (null != super.getId()) { result.setAttributeNS( null, EncryptionConstants._ATT_ID, super.getId()); } if (null != super.getType()) { result.setAttributeNS( null, EncryptionConstants._ATT_TYPE, super.getType().toString()); } if (null != super.getMimeType()) { result.setAttributeNS(null, EncryptionConstants._ATT_MIMETYPE, super.getMimeType()); } if (null != super.getEncoding()) { result.setAttributeNS(null, Constants._ATT_ENCODING, super.getEncoding().toString()); } if (null != getRecipient()) { result.setAttributeNS(null, EncryptionConstants._ATT_RECIPIENT, getRecipient()); } if (null != super.getEncryptionMethod()) { result.appendChild(((EncryptionMethodImpl) super.getEncryptionMethod()).toElement()); } if (null != super.getKeyInfo()) { result.appendChild(super.getKeyInfo().getElement()); } result.appendChild( ((CipherDataImpl) super.getCipherData()).toElement()); if (null != super.getEncryptionProperties()) { result.appendChild(((EncryptionPropertiesImpl) super.getEncryptionProperties()).toElement()); } if (referenceList != null && !referenceList.isEmpty()) { result.appendChild(((ReferenceListImpl) getReferenceList()).toElement()); } if (null != carriedName) { Element element = ElementProxy.createElementForFamily( _contextDocument, EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_CARRIEDKEYNAME); Node node = _contextDocument.createTextNode(carriedName); element.appendChild(node); result.appendChild(element); } return (result); } } private abstract class EncryptedTypeImpl { private String id = null; private String type = null; private String mimeType = null; private String encoding = null; private EncryptionMethod encryptionMethod = null; private KeyInfo keyInfo = null; private CipherData cipherData = null; private EncryptionProperties encryptionProperties = null; protected EncryptedTypeImpl(CipherData data) { cipherData = data; } /** * * @return */ public String getId() { return (id); } /** * * @param id */ public void setId(String id) { this.id = id; } /** * * @return */ public String getType() { return (type); } /** * * @param type */ public void setType(String type) { URI tmpType = null; try { tmpType = new URI(type); } catch (URI.MalformedURIException mfue) { // complain } this.type = tmpType.toString(); } /** * * @return */ public String getMimeType() { return (mimeType); } /** * * @param type */ public void setMimeType(String type) { mimeType = type; } /** * * @return */ public String getEncoding() { return (encoding); } /** * * @param encoding */ public void setEncoding(String encoding) { URI tmpEncoding = null; try { tmpEncoding = new URI(encoding); } catch (URI.MalformedURIException mfue) { // complain } this.encoding = tmpEncoding.toString(); } /** * * @return */ public EncryptionMethod getEncryptionMethod() { return (encryptionMethod); } /** * * @param method */ public void setEncryptionMethod(EncryptionMethod method) { encryptionMethod = method; } /** * * @return */ public KeyInfo getKeyInfo() { return (keyInfo); } /** * * @param info */ public void setKeyInfo(KeyInfo info) { keyInfo = info; } /** * * @return */ public CipherData getCipherData() { return (cipherData); } /** * * @return */ public EncryptionProperties getEncryptionProperties() { return (encryptionProperties); } /** * * @param properties */ public void setEncryptionProperties( EncryptionProperties properties) { encryptionProperties = properties; } } // <complexType name='EncryptionMethodType' mixed='true'> // <sequence> // <element name='KeySize' minOccurs='0' type='xenc:KeySizeType'/> // <element name='OAEPparams' minOccurs='0' type='base64Binary'/> // <any namespace='##other' minOccurs='0' maxOccurs='unbounded'/> // </sequence> // <attribute name='Algorithm' type='anyURI' use='required'/> // </complexType> private class EncryptionMethodImpl implements EncryptionMethod { private String algorithm = null; private int keySize = Integer.MIN_VALUE; private byte[] oaepParams = null; private List encryptionMethodInformation = null; /** * * @param algorithm */ public EncryptionMethodImpl(String algorithm) { URI tmpAlgorithm = null; try { tmpAlgorithm = new URI(algorithm); } catch (URI.MalformedURIException mfue) { // complain } this.algorithm = tmpAlgorithm.toString(); encryptionMethodInformation = new LinkedList(); } /** @inheritDoc */ public String getAlgorithm() { return (algorithm); } /** @inheritDoc */ public int getKeySize() { return (keySize); } /** @inheritDoc */ public void setKeySize(int size) { keySize = size; } /** @inheritDoc */ public byte[] getOAEPparams() { return (oaepParams); } /** @inheritDoc */ public void setOAEPparams(byte[] params) { oaepParams = params; } /** @inheritDoc */ public Iterator getEncryptionMethodInformation() { return (encryptionMethodInformation.iterator()); } /** @inheritDoc */ public void addEncryptionMethodInformation(Element info) { encryptionMethodInformation.add(info); } /** @inheritDoc */ public void removeEncryptionMethodInformation(Element info) { encryptionMethodInformation.remove(info); } // <complexType name='EncryptionMethodType' mixed='true'> // <sequence> // <element name='KeySize' minOccurs='0' type='xenc:KeySizeType'/> // <element name='OAEPparams' minOccurs='0' type='base64Binary'/> // <any namespace='##other' minOccurs='0' maxOccurs='unbounded'/> // </sequence> // <attribute name='Algorithm' type='anyURI' use='required'/> // </complexType> Element toElement() { Element result = ElementProxy.createElementForFamily( _contextDocument, EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_ENCRYPTIONMETHOD); result.setAttributeNS(null, EncryptionConstants._ATT_ALGORITHM, algorithm.toString()); if (keySize > 0) { result.appendChild( ElementProxy.createElementForFamily(_contextDocument, EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_KEYSIZE).appendChild( _contextDocument.createTextNode( String.valueOf(keySize)))); } if (null != oaepParams) { result.appendChild( ElementProxy.createElementForFamily(_contextDocument, EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_OAEPPARAMS).appendChild( _contextDocument.createTextNode( new String(oaepParams)))); } if (!encryptionMethodInformation.isEmpty()) { Iterator itr = encryptionMethodInformation.iterator(); result.appendChild((Element) itr.next()); } return (result); } } // <element name='EncryptionProperties' type='xenc:EncryptionPropertiesType'/> // <complexType name='EncryptionPropertiesType'> // <sequence> // <element ref='xenc:EncryptionProperty' maxOccurs='unbounded'/> // </sequence> // <attribute name='Id' type='ID' use='optional'/> // </complexType> private class EncryptionPropertiesImpl implements EncryptionProperties { private String id = null; private List encryptionProperties = null; /** * * */ public EncryptionPropertiesImpl() { encryptionProperties = new LinkedList(); } /** @inheritDoc */ public String getId() { return (id); } /** @inheritDoc */ public void setId(String id) { this.id = id; } /** @inheritDoc */ public Iterator getEncryptionProperties() { return (encryptionProperties.iterator()); } /** @inheritDoc */ public void addEncryptionProperty(EncryptionProperty property) { encryptionProperties.add(property); } /** @inheritDoc */ public void removeEncryptionProperty(EncryptionProperty property) { encryptionProperties.remove(property); } // <element name='EncryptionProperties' type='xenc:EncryptionPropertiesType'/> // <complexType name='EncryptionPropertiesType'> // <sequence> // <element ref='xenc:EncryptionProperty' maxOccurs='unbounded'/> // </sequence> // <attribute name='Id' type='ID' use='optional'/> // </complexType> Element toElement() { Element result = ElementProxy.createElementForFamily( _contextDocument, EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_ENCRYPTIONPROPERTIES); if (null != id) { result.setAttributeNS(null, EncryptionConstants._ATT_ID, id); } Iterator itr = getEncryptionProperties(); while (itr.hasNext()) { result.appendChild(((EncryptionPropertyImpl) itr.next()).toElement()); } return (result); } } // <element name='EncryptionProperty' type='xenc:EncryptionPropertyType'/> // <complexType name='EncryptionPropertyType' mixed='true'> // <choice maxOccurs='unbounded'> // <any namespace='##other' processContents='lax'/> // </choice> // <attribute name='Target' type='anyURI' use='optional'/> // <attribute name='Id' type='ID' use='optional'/> // <anyAttribute namespace="http://www.w3.org/XML/1998/namespace"/> // </complexType> private class EncryptionPropertyImpl implements EncryptionProperty { private String target = null; private String id = null; private String attributeName = null; private String attributeValue = null; private List encryptionInformation = null; /** * * */ public EncryptionPropertyImpl() { encryptionInformation = new LinkedList(); } /** @inheritDoc */ public String getTarget() { return (target); } /** @inheritDoc */ public void setTarget(String target) { URI tmpTarget = null; try { tmpTarget = new URI(target); } catch (URI.MalformedURIException mfue) { // complain } this.target = tmpTarget.toString(); } /** @inheritDoc */ public String getId() { return (id); } /** @inheritDoc */ public void setId(String id) { this.id = id; } /** @inheritDoc */ public String getAttribute(String attribute) { return (attributeValue); } /** @inheritDoc */ public void setAttribute(String attribute, String value) { attributeName = attribute; attributeValue = value; } /** @inheritDoc */ public Iterator getEncryptionInformation() { return (encryptionInformation.iterator()); } /** @inheritDoc */ public void addEncryptionInformation(Element info) { encryptionInformation.add(info); } /** @inheritDoc */ public void removeEncryptionInformation(Element info) { encryptionInformation.remove(info); } // <element name='EncryptionProperty' type='xenc:EncryptionPropertyType'/> // <complexType name='EncryptionPropertyType' mixed='true'> // <choice maxOccurs='unbounded'> // <any namespace='##other' processContents='lax'/> // </choice> // <attribute name='Target' type='anyURI' use='optional'/> // <attribute name='Id' type='ID' use='optional'/> // <anyAttribute namespace="http://www.w3.org/XML/1998/namespace"/> // </complexType> Element toElement() { Element result = ElementProxy.createElementForFamily( _contextDocument, EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_ENCRYPTIONPROPERTY); if (null != target) { result.setAttributeNS(null, EncryptionConstants._ATT_TARGET, target.toString()); } if (null != id) { result.setAttributeNS(null, EncryptionConstants._ATT_ID, id); } // TODO: figure out the anyAttribyte stuff... // TODO: figure out the any stuff... return (result); } } // <complexType name='TransformsType'> // <sequence> // <element ref='ds:Transform' maxOccurs='unbounded'/> // </sequence> // </complexType> private class TransformsImpl extends com.sun.org.apache.xml.internal.security.transforms.Transforms implements Transforms { /** * Construct Transforms */ public TransformsImpl() { super(_contextDocument); } /** * * @param doc */ public TransformsImpl(Document doc) { super(doc); } /** * * @param element * @throws XMLSignatureException * @throws InvalidTransformException * @throws XMLSecurityException * @throws TransformationException */ public TransformsImpl(Element element) throws XMLSignatureException, InvalidTransformException, XMLSecurityException, TransformationException { super(element, ""); } /** * * @return */ public Element toElement() { if (_doc == null) _doc = _contextDocument; return getElement(); } /** @inheritDoc */ public com.sun.org.apache.xml.internal.security.transforms.Transforms getDSTransforms() { return (this); } // Over-ride the namespace /** @inheritDoc */ public String getBaseNamespace() { return EncryptionConstants.EncryptionSpecNS; } } //<element name='ReferenceList'> // <complexType> // <choice minOccurs='1' maxOccurs='unbounded'> // <element name='DataReference' type='xenc:ReferenceType'/> // <element name='KeyReference' type='xenc:ReferenceType'/> // </choice> // </complexType> //</element> private class ReferenceListImpl implements ReferenceList { private Class sentry; private List references; /** * * @param type */ public ReferenceListImpl(int type) { if (type == ReferenceList.DATA_REFERENCE) { sentry = DataReference.class; } else if (type == ReferenceList.KEY_REFERENCE) { sentry = KeyReference.class; } else { throw new IllegalArgumentException(); } references = new LinkedList(); } /** @inheritDoc */ public void add(Reference reference) { if (!reference.getClass().equals(sentry)) { throw new IllegalArgumentException(); } references.add(reference); } /** @inheritDoc */ public void remove(Reference reference) { if (!reference.getClass().equals(sentry)) { throw new IllegalArgumentException(); } references.remove(reference); } /** @inheritDoc */ public int size() { return (references.size()); } /** @inheritDoc */ public boolean isEmpty() { return (references.isEmpty()); } /** @inheritDoc */ public Iterator getReferences() { return (references.iterator()); } Element toElement() { Element result = ElementProxy.createElementForFamily( _contextDocument, EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_REFERENCELIST); Iterator eachReference = references.iterator(); while (eachReference.hasNext()) { Reference reference = (Reference) eachReference.next(); result.appendChild( ((ReferenceImpl) reference).toElement()); } return (result); } /** @inheritDoc */ public Reference newDataReference(String uri) { return (new DataReference(uri)); } /** @inheritDoc */ public Reference newKeyReference(String uri) { return (new KeyReference(uri)); } /** * <code>ReferenceImpl</code> is an implementation of * <code>Reference</code>. * * @see Reference */ private abstract class ReferenceImpl implements Reference { private String uri; private List referenceInformation; ReferenceImpl(String _uri) { this.uri = _uri; referenceInformation = new LinkedList(); } /** @inheritDoc */ public String getURI() { return (uri); } /** @inheritDoc */ public Iterator getElementRetrievalInformation() { return (referenceInformation.iterator()); } /** @inheritDoc */ public void setURI(String _uri) { this.uri = _uri; } /** @inheritDoc */ public void removeElementRetrievalInformation(Element node) { referenceInformation.remove(node); } /** @inheritDoc */ public void addElementRetrievalInformation(Element node) { referenceInformation.add(node); } /** * * @return */ public abstract Element toElement(); Element toElement(String tagName) { Element result = ElementProxy.createElementForFamily( _contextDocument, EncryptionConstants.EncryptionSpecNS, tagName); result.setAttribute(EncryptionConstants._ATT_URI, uri); // TODO: Need to martial referenceInformation // Figure out how to make this work.. // <any namespace="##other" minOccurs="0" maxOccurs="unbounded"/> return (result); } } private class DataReference extends ReferenceImpl { DataReference(String uri) { super(uri); } /** @inheritDoc */ public Element toElement() { return super.toElement(EncryptionConstants._TAG_DATAREFERENCE); } } private class KeyReference extends ReferenceImpl { KeyReference(String uri) { super (uri); } /** @inheritDoc */ public Element toElement() { return super.toElement(EncryptionConstants._TAG_KEYREFERENCE); } } } } }