src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/encryption/XMLCipher.java
branchhttp-client-branch
changeset 56783 7add69e2fb68
parent 56781 4a32a40ce131
parent 50643 f2d94a0619a2
child 56785 62937a37a291
equal deleted inserted replaced
56781:4a32a40ce131 56783:7add69e2fb68
     1 /*
       
     2  * reserved comment block
       
     3  * DO NOT REMOVE OR ALTER!
       
     4  */
       
     5 /**
       
     6  * Licensed to the Apache Software Foundation (ASF) under one
       
     7  * or more contributor license agreements. See the NOTICE file
       
     8  * distributed with this work for additional information
       
     9  * regarding copyright ownership. The ASF licenses this file
       
    10  * to you under the Apache License, Version 2.0 (the
       
    11  * "License"); you may not use this file except in compliance
       
    12  * with the License. You may obtain a copy of the License at
       
    13  *
       
    14  * http://www.apache.org/licenses/LICENSE-2.0
       
    15  *
       
    16  * Unless required by applicable law or agreed to in writing,
       
    17  * software distributed under the License is distributed on an
       
    18  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
       
    19  * KIND, either express or implied. See the License for the
       
    20  * specific language governing permissions and limitations
       
    21  * under the License.
       
    22  */
       
    23 package com.sun.org.apache.xml.internal.security.encryption;
       
    24 
       
    25 import java.io.ByteArrayOutputStream;
       
    26 import java.io.InputStream;
       
    27 import java.io.UnsupportedEncodingException;
       
    28 import java.net.URI;
       
    29 import java.net.URISyntaxException;
       
    30 import java.security.InvalidAlgorithmParameterException;
       
    31 import java.security.InvalidKeyException;
       
    32 import java.security.Key;
       
    33 import java.security.NoSuchAlgorithmException;
       
    34 import java.security.NoSuchProviderException;
       
    35 import java.security.SecureRandom;
       
    36 import java.security.spec.MGF1ParameterSpec;
       
    37 import java.util.ArrayList;
       
    38 import java.util.HashMap;
       
    39 import java.util.Iterator;
       
    40 import java.util.LinkedList;
       
    41 import java.util.List;
       
    42 import java.util.Map;
       
    43 
       
    44 import javax.crypto.BadPaddingException;
       
    45 import javax.crypto.Cipher;
       
    46 import javax.crypto.IllegalBlockSizeException;
       
    47 import javax.crypto.NoSuchPaddingException;
       
    48 import javax.crypto.spec.IvParameterSpec;
       
    49 import javax.crypto.spec.OAEPParameterSpec;
       
    50 import javax.crypto.spec.PSource;
       
    51 
       
    52 import com.sun.org.apache.xml.internal.security.algorithms.JCEMapper;
       
    53 import com.sun.org.apache.xml.internal.security.algorithms.MessageDigestAlgorithm;
       
    54 import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer;
       
    55 import com.sun.org.apache.xml.internal.security.c14n.InvalidCanonicalizerException;
       
    56 import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
       
    57 import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException;
       
    58 import com.sun.org.apache.xml.internal.security.keys.KeyInfo;
       
    59 import com.sun.org.apache.xml.internal.security.keys.keyresolver.KeyResolverException;
       
    60 import com.sun.org.apache.xml.internal.security.keys.keyresolver.KeyResolverSpi;
       
    61 import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.EncryptedKeyResolver;
       
    62 import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException;
       
    63 import com.sun.org.apache.xml.internal.security.transforms.InvalidTransformException;
       
    64 import com.sun.org.apache.xml.internal.security.transforms.TransformationException;
       
    65 import com.sun.org.apache.xml.internal.security.utils.Base64;
       
    66 import com.sun.org.apache.xml.internal.security.utils.Constants;
       
    67 import com.sun.org.apache.xml.internal.security.utils.ElementProxy;
       
    68 import com.sun.org.apache.xml.internal.security.utils.EncryptionConstants;
       
    69 import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
       
    70 import org.w3c.dom.Attr;
       
    71 import org.w3c.dom.Document;
       
    72 import org.w3c.dom.Element;
       
    73 import org.w3c.dom.Node;
       
    74 import org.w3c.dom.NodeList;
       
    75 
       
    76 /**
       
    77  * <code>XMLCipher</code> encrypts and decrypts the contents of
       
    78  * <code>Document</code>s, <code>Element</code>s and <code>Element</code>
       
    79  * contents. It was designed to resemble <code>javax.crypto.Cipher</code> in
       
    80  * order to facilitate understanding of its functioning.
       
    81  *
       
    82  * @author Axl Mattheus (Sun Microsystems)
       
    83  * @author Christian Geuer-Pollmann
       
    84  */
       
    85 public class XMLCipher {
       
    86 
       
    87     private static java.util.logging.Logger log =
       
    88         java.util.logging.Logger.getLogger(XMLCipher.class.getName());
       
    89 
       
    90     /** Triple DES EDE (192 bit key) in CBC mode */
       
    91     public static final String TRIPLEDES =
       
    92         EncryptionConstants.ALGO_ID_BLOCKCIPHER_TRIPLEDES;
       
    93 
       
    94     /** AES 128 Cipher */
       
    95     public static final String AES_128 =
       
    96         EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128;
       
    97 
       
    98     /** AES 256 Cipher */
       
    99     public static final String AES_256 =
       
   100         EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256;
       
   101 
       
   102     /** AES 192 Cipher */
       
   103     public static final String AES_192 =
       
   104         EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES192;
       
   105 
       
   106     /** AES 128 GCM Cipher */
       
   107     public static final String AES_128_GCM =
       
   108         EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM;
       
   109 
       
   110     /** AES 192 GCM Cipher */
       
   111     public static final String AES_192_GCM =
       
   112         EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES192_GCM;
       
   113 
       
   114     /** AES 256 GCM Cipher */
       
   115     public static final String AES_256_GCM =
       
   116         EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256_GCM;
       
   117 
       
   118     /** RSA 1.5 Cipher */
       
   119     public static final String RSA_v1dot5 =
       
   120         EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSA15;
       
   121 
       
   122     /** RSA OAEP Cipher */
       
   123     public static final String RSA_OAEP =
       
   124         EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSAOAEP;
       
   125 
       
   126     /** RSA OAEP Cipher */
       
   127     public static final String RSA_OAEP_11 =
       
   128         EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSAOAEP_11;
       
   129 
       
   130     /** DIFFIE_HELLMAN Cipher */
       
   131     public static final String DIFFIE_HELLMAN =
       
   132         EncryptionConstants.ALGO_ID_KEYAGREEMENT_DH;
       
   133 
       
   134     /** Triple DES EDE (192 bit key) in CBC mode KEYWRAP*/
       
   135     public static final String TRIPLEDES_KeyWrap =
       
   136         EncryptionConstants.ALGO_ID_KEYWRAP_TRIPLEDES;
       
   137 
       
   138     /** AES 128 Cipher KeyWrap */
       
   139     public static final String AES_128_KeyWrap =
       
   140         EncryptionConstants.ALGO_ID_KEYWRAP_AES128;
       
   141 
       
   142     /** AES 256 Cipher KeyWrap */
       
   143     public static final String AES_256_KeyWrap =
       
   144         EncryptionConstants.ALGO_ID_KEYWRAP_AES256;
       
   145 
       
   146     /** AES 192 Cipher KeyWrap */
       
   147     public static final String AES_192_KeyWrap =
       
   148         EncryptionConstants.ALGO_ID_KEYWRAP_AES192;
       
   149 
       
   150     /** SHA1 Cipher */
       
   151     public static final String SHA1 =
       
   152         Constants.ALGO_ID_DIGEST_SHA1;
       
   153 
       
   154     /** SHA256 Cipher */
       
   155     public static final String SHA256 =
       
   156         MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA256;
       
   157 
       
   158     /** SHA512 Cipher */
       
   159     public static final String SHA512 =
       
   160         MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA512;
       
   161 
       
   162     /** RIPEMD Cipher */
       
   163     public static final String RIPEMD_160 =
       
   164         MessageDigestAlgorithm.ALGO_ID_DIGEST_RIPEMD160;
       
   165 
       
   166     /** XML Signature NS */
       
   167     public static final String XML_DSIG =
       
   168         Constants.SignatureSpecNS;
       
   169 
       
   170     /** N14C_XML */
       
   171     public static final String N14C_XML =
       
   172         Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS;
       
   173 
       
   174     /** N14C_XML with comments*/
       
   175     public static final String N14C_XML_WITH_COMMENTS =
       
   176         Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS;
       
   177 
       
   178     /** N14C_XML exclusive */
       
   179     public static final String EXCL_XML_N14C =
       
   180         Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS;
       
   181 
       
   182     /** N14C_XML exclusive with comments*/
       
   183     public static final String EXCL_XML_N14C_WITH_COMMENTS =
       
   184         Canonicalizer.ALGO_ID_C14N_EXCL_WITH_COMMENTS;
       
   185 
       
   186     /** N14C_PHYSICAL preserve the physical representation*/
       
   187     public static final String PHYSICAL_XML_N14C =
       
   188         Canonicalizer.ALGO_ID_C14N_PHYSICAL;
       
   189 
       
   190     /** Base64 encoding */
       
   191     public static final String BASE64_ENCODING =
       
   192         com.sun.org.apache.xml.internal.security.transforms.Transforms.TRANSFORM_BASE64_DECODE;
       
   193 
       
   194     /** ENCRYPT Mode */
       
   195     public static final int ENCRYPT_MODE = Cipher.ENCRYPT_MODE;
       
   196 
       
   197     /** DECRYPT Mode */
       
   198     public static final int DECRYPT_MODE = Cipher.DECRYPT_MODE;
       
   199 
       
   200     /** UNWRAP Mode */
       
   201     public static final int UNWRAP_MODE  = Cipher.UNWRAP_MODE;
       
   202 
       
   203     /** WRAP Mode */
       
   204     public static final int WRAP_MODE    = Cipher.WRAP_MODE;
       
   205 
       
   206     private static final String ENC_ALGORITHMS = TRIPLEDES + "\n" +
       
   207     AES_128 + "\n" + AES_256 + "\n" + AES_192 + "\n" + RSA_v1dot5 + "\n" +
       
   208     RSA_OAEP + "\n" + RSA_OAEP_11 + "\n" + TRIPLEDES_KeyWrap + "\n" +
       
   209     AES_128_KeyWrap + "\n" + AES_256_KeyWrap + "\n" + AES_192_KeyWrap + "\n" +
       
   210     AES_128_GCM + "\n" + AES_192_GCM + "\n" + AES_256_GCM + "\n";
       
   211 
       
   212     /** Cipher created during initialisation that is used for encryption */
       
   213     private Cipher contextCipher;
       
   214 
       
   215     /** Mode that the XMLCipher object is operating in */
       
   216     private int cipherMode = Integer.MIN_VALUE;
       
   217 
       
   218     /** URI of algorithm that is being used for cryptographic operation */
       
   219     private String algorithm = null;
       
   220 
       
   221     /** Cryptographic provider requested by caller */
       
   222     private String requestedJCEProvider = null;
       
   223 
       
   224     /** Holds c14n to serialize, if initialized then _always_ use this c14n to serialize */
       
   225     private Canonicalizer canon;
       
   226 
       
   227     /** Used for creation of DOM nodes in WRAP and ENCRYPT modes */
       
   228     private Document contextDocument;
       
   229 
       
   230     /** Instance of factory used to create XML Encryption objects */
       
   231     private Factory factory;
       
   232 
       
   233     /** Serializer class for going to/from UTF-8 */
       
   234     private Serializer serializer;
       
   235 
       
   236     /** Local copy of user's key */
       
   237     private Key key;
       
   238 
       
   239     /** Local copy of the kek (used to decrypt EncryptedKeys during a
       
   240      *  DECRYPT_MODE operation */
       
   241     private Key kek;
       
   242 
       
   243     // The EncryptedKey being built (part of a WRAP operation) or read
       
   244     // (part of an UNWRAP operation)
       
   245     private EncryptedKey ek;
       
   246 
       
   247     // The EncryptedData being built (part of a WRAP operation) or read
       
   248     // (part of an UNWRAP operation)
       
   249     private EncryptedData ed;
       
   250 
       
   251     private SecureRandom random;
       
   252 
       
   253     private boolean secureValidation;
       
   254 
       
   255     private String digestAlg;
       
   256 
       
   257     /** List of internal KeyResolvers for DECRYPT and UNWRAP modes. */
       
   258     private List<KeyResolverSpi> internalKeyResolvers;
       
   259 
       
   260     /**
       
   261      * Set the Serializer algorithm to use
       
   262      */
       
   263     public void setSerializer(Serializer serializer) {
       
   264         this.serializer = serializer;
       
   265         serializer.setCanonicalizer(this.canon);
       
   266     }
       
   267 
       
   268     /**
       
   269      * Get the Serializer algorithm to use
       
   270      */
       
   271     public Serializer getSerializer() {
       
   272         return serializer;
       
   273     }
       
   274 
       
   275     /**
       
   276      * Creates a new <code>XMLCipher</code>.
       
   277      *
       
   278      * @param transformation    the name of the transformation, e.g.,
       
   279      *                          <code>XMLCipher.TRIPLEDES</code>. If null the XMLCipher can only
       
   280      *                          be used for decrypt or unwrap operations where the encryption method
       
   281      *                          is defined in the <code>EncryptionMethod</code> element.
       
   282      * @param provider          the JCE provider that supplies the transformation,
       
   283      *                          if null use the default provider.
       
   284      * @param canon             the name of the c14n algorithm, if
       
   285      *                          <code>null</code> use standard serializer
       
   286      * @param digestMethod      An optional digestMethod to use.
       
   287      */
       
   288     private XMLCipher(
       
   289         String transformation,
       
   290         String provider,
       
   291         String canonAlg,
       
   292         String digestMethod
       
   293     ) throws XMLEncryptionException {
       
   294         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
   295             log.log(java.util.logging.Level.FINE, "Constructing XMLCipher...");
       
   296         }
       
   297 
       
   298         factory = new Factory();
       
   299 
       
   300         algorithm = transformation;
       
   301         requestedJCEProvider = provider;
       
   302         digestAlg = digestMethod;
       
   303 
       
   304         // Create a canonicalizer - used when serializing DOM to octets
       
   305         // prior to encryption (and for the reverse)
       
   306 
       
   307         try {
       
   308             if (canonAlg == null) {
       
   309                 // The default is to preserve the physical representation.
       
   310                 this.canon = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_PHYSICAL);
       
   311             } else {
       
   312                 this.canon = Canonicalizer.getInstance(canonAlg);
       
   313             }
       
   314         } catch (InvalidCanonicalizerException ice) {
       
   315             throw new XMLEncryptionException("empty", ice);
       
   316         }
       
   317 
       
   318         if (serializer == null) {
       
   319             serializer = new DocumentSerializer();
       
   320         }
       
   321         serializer.setCanonicalizer(this.canon);
       
   322 
       
   323         if (transformation != null) {
       
   324             contextCipher = constructCipher(transformation, digestMethod);
       
   325         }
       
   326     }
       
   327 
       
   328     /**
       
   329      * Checks to ensure that the supplied algorithm is valid.
       
   330      *
       
   331      * @param algorithm the algorithm to check.
       
   332      * @return true if the algorithm is valid, otherwise false.
       
   333      * @since 1.0.
       
   334      */
       
   335     private static boolean isValidEncryptionAlgorithm(String algorithm) {
       
   336         return (
       
   337             algorithm.equals(TRIPLEDES) ||
       
   338             algorithm.equals(AES_128) ||
       
   339             algorithm.equals(AES_256) ||
       
   340             algorithm.equals(AES_192) ||
       
   341             algorithm.equals(AES_128_GCM) ||
       
   342             algorithm.equals(AES_192_GCM) ||
       
   343             algorithm.equals(AES_256_GCM) ||
       
   344             algorithm.equals(RSA_v1dot5) ||
       
   345             algorithm.equals(RSA_OAEP) ||
       
   346             algorithm.equals(RSA_OAEP_11) ||
       
   347             algorithm.equals(TRIPLEDES_KeyWrap) ||
       
   348             algorithm.equals(AES_128_KeyWrap) ||
       
   349             algorithm.equals(AES_256_KeyWrap) ||
       
   350             algorithm.equals(AES_192_KeyWrap)
       
   351         );
       
   352     }
       
   353 
       
   354     /**
       
   355      * Validate the transformation argument of getInstance or getProviderInstance
       
   356      *
       
   357      * @param transformation the name of the transformation, e.g.,
       
   358      *   <code>XMLCipher.TRIPLEDES</code> which is shorthand for
       
   359      *   &quot;http://www.w3.org/2001/04/xmlenc#tripledes-cbc&quot;
       
   360      */
       
   361     private static void validateTransformation(String transformation) {
       
   362         if (null == transformation) {
       
   363             throw new NullPointerException("Transformation unexpectedly null...");
       
   364         }
       
   365         if (!isValidEncryptionAlgorithm(transformation)) {
       
   366             log.log(java.util.logging.Level.WARNING, "Algorithm non-standard, expected one of " + ENC_ALGORITHMS);
       
   367         }
       
   368     }
       
   369 
       
   370     /**
       
   371      * Returns an <code>XMLCipher</code> that implements the specified
       
   372      * transformation and operates on the specified context document.
       
   373      * <p>
       
   374      * If the default provider package supplies an implementation of the
       
   375      * requested transformation, an instance of Cipher containing that
       
   376      * implementation is returned. If the transformation is not available in
       
   377      * the default provider package, other provider packages are searched.
       
   378      * <p>
       
   379      * <b>NOTE<sub>1</sub>:</b> The transformation name does not follow the same
       
   380      * pattern as that outlined in the Java Cryptography Extension Reference
       
   381      * Guide but rather that specified by the XML Encryption Syntax and
       
   382      * Processing document. The rational behind this is to make it easier for a
       
   383      * novice at writing Java Encryption software to use the library.
       
   384      * <p>
       
   385      * <b>NOTE<sub>2</sub>:</b> <code>getInstance()</code> does not follow the
       
   386      * same pattern regarding exceptional conditions as that used in
       
   387      * <code>javax.crypto.Cipher</code>. Instead, it only throws an
       
   388      * <code>XMLEncryptionException</code> which wraps an underlying exception.
       
   389      * The stack trace from the exception should be self explanatory.
       
   390      *
       
   391      * @param transformation the name of the transformation, e.g.,
       
   392      *   <code>XMLCipher.TRIPLEDES</code> which is shorthand for
       
   393      *   &quot;http://www.w3.org/2001/04/xmlenc#tripledes-cbc&quot;
       
   394      * @throws XMLEncryptionException
       
   395      * @return the XMLCipher
       
   396      * @see javax.crypto.Cipher#getInstance(java.lang.String)
       
   397      */
       
   398     public static XMLCipher getInstance(String transformation) throws XMLEncryptionException {
       
   399         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
   400             log.log(java.util.logging.Level.FINE, "Getting XMLCipher with transformation");
       
   401         }
       
   402         validateTransformation(transformation);
       
   403         return new XMLCipher(transformation, null, null, null);
       
   404     }
       
   405 
       
   406     /**
       
   407      * Returns an <code>XMLCipher</code> that implements the specified
       
   408      * transformation, operates on the specified context document and serializes
       
   409      * the document with the specified canonicalization algorithm before it
       
   410      * encrypts the document.
       
   411      * <p>
       
   412      *
       
   413      * @param transformation    the name of the transformation
       
   414      * @param canon             the name of the c14n algorithm, if <code>null</code> use
       
   415      *                          standard serializer
       
   416      * @return the XMLCipher
       
   417      * @throws XMLEncryptionException
       
   418      */
       
   419     public static XMLCipher getInstance(String transformation, String canon)
       
   420         throws XMLEncryptionException {
       
   421         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
   422             log.log(java.util.logging.Level.FINE, "Getting XMLCipher with transformation and c14n algorithm");
       
   423         }
       
   424         validateTransformation(transformation);
       
   425         return new XMLCipher(transformation, null, canon, null);
       
   426     }
       
   427 
       
   428     /**
       
   429      * Returns an <code>XMLCipher</code> that implements the specified
       
   430      * transformation, operates on the specified context document and serializes
       
   431      * the document with the specified canonicalization algorithm before it
       
   432      * encrypts the document.
       
   433      * <p>
       
   434      *
       
   435      * @param transformation    the name of the transformation
       
   436      * @param canon             the name of the c14n algorithm, if <code>null</code> use
       
   437      *                          standard serializer
       
   438      * @param digestMethod      An optional digestMethod to use
       
   439      * @return the XMLCipher
       
   440      * @throws XMLEncryptionException
       
   441      */
       
   442     public static XMLCipher getInstance(String transformation, String canon, String digestMethod)
       
   443         throws XMLEncryptionException {
       
   444         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
   445             log.log(java.util.logging.Level.FINE, "Getting XMLCipher with transformation and c14n algorithm");
       
   446         }
       
   447         validateTransformation(transformation);
       
   448         return new XMLCipher(transformation, null, canon, digestMethod);
       
   449     }
       
   450 
       
   451     /**
       
   452      * Returns an <code>XMLCipher</code> that implements the specified
       
   453      * transformation and operates on the specified context document.
       
   454      *
       
   455      * @param transformation    the name of the transformation
       
   456      * @param provider          the JCE provider that supplies the transformation
       
   457      * @return the XMLCipher
       
   458      * @throws XMLEncryptionException
       
   459      */
       
   460     public static XMLCipher getProviderInstance(String transformation, String provider)
       
   461         throws XMLEncryptionException {
       
   462         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
   463             log.log(java.util.logging.Level.FINE, "Getting XMLCipher with transformation and provider");
       
   464         }
       
   465         if (null == provider) {
       
   466             throw new NullPointerException("Provider unexpectedly null..");
       
   467         }
       
   468         validateTransformation(transformation);
       
   469         return new XMLCipher(transformation, provider, null, null);
       
   470     }
       
   471 
       
   472     /**
       
   473      * Returns an <code>XMLCipher</code> that implements the specified
       
   474      * transformation, operates on the specified context document and serializes
       
   475      * the document with the specified canonicalization algorithm before it
       
   476      * encrypts the document.
       
   477      * <p>
       
   478      *
       
   479      * @param transformation    the name of the transformation
       
   480      * @param provider          the JCE provider that supplies the transformation
       
   481      * @param canon             the name of the c14n algorithm, if <code>null</code> use standard
       
   482      *                          serializer
       
   483      * @return the XMLCipher
       
   484      * @throws XMLEncryptionException
       
   485      */
       
   486     public static XMLCipher getProviderInstance(
       
   487         String transformation, String provider, String canon
       
   488     ) throws XMLEncryptionException {
       
   489         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
   490             log.log(java.util.logging.Level.FINE, "Getting XMLCipher with transformation, provider and c14n algorithm");
       
   491         }
       
   492         if (null == provider) {
       
   493             throw new NullPointerException("Provider unexpectedly null..");
       
   494         }
       
   495         validateTransformation(transformation);
       
   496         return new XMLCipher(transformation, provider, canon, null);
       
   497     }
       
   498 
       
   499     /**
       
   500      * Returns an <code>XMLCipher</code> that implements the specified
       
   501      * transformation, operates on the specified context document and serializes
       
   502      * the document with the specified canonicalization algorithm before it
       
   503      * encrypts the document.
       
   504      * <p>
       
   505      *
       
   506      * @param transformation    the name of the transformation
       
   507      * @param provider          the JCE provider that supplies the transformation
       
   508      * @param canon             the name of the c14n algorithm, if <code>null</code> use standard
       
   509      *                          serializer
       
   510      * @param digestMethod      An optional digestMethod to use
       
   511      * @return the XMLCipher
       
   512      * @throws XMLEncryptionException
       
   513      */
       
   514     public static XMLCipher getProviderInstance(
       
   515         String transformation, String provider, String canon, String digestMethod
       
   516     ) throws XMLEncryptionException {
       
   517         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
   518             log.log(java.util.logging.Level.FINE, "Getting XMLCipher with transformation, provider and c14n algorithm");
       
   519         }
       
   520         if (null == provider) {
       
   521             throw new NullPointerException("Provider unexpectedly null..");
       
   522         }
       
   523         validateTransformation(transformation);
       
   524         return new XMLCipher(transformation, provider, canon, digestMethod);
       
   525     }
       
   526 
       
   527     /**
       
   528      * Returns an <code>XMLCipher</code> that implements no specific
       
   529      * transformation, and can therefore only be used for decrypt or
       
   530      * unwrap operations where the encryption method is defined in the
       
   531      * <code>EncryptionMethod</code> element.
       
   532      *
       
   533      * @return The XMLCipher
       
   534      * @throws XMLEncryptionException
       
   535      */
       
   536     public static XMLCipher getInstance() throws XMLEncryptionException {
       
   537         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
   538             log.log(java.util.logging.Level.FINE, "Getting XMLCipher with no arguments");
       
   539         }
       
   540         return new XMLCipher(null, null, null, null);
       
   541     }
       
   542 
       
   543     /**
       
   544      * Returns an <code>XMLCipher</code> that implements no specific
       
   545      * transformation, and can therefore only be used for decrypt or
       
   546      * unwrap operations where the encryption method is defined in the
       
   547      * <code>EncryptionMethod</code> element.
       
   548      *
       
   549      * Allows the caller to specify a provider that will be used for
       
   550      * cryptographic operations.
       
   551      *
       
   552      * @param provider          the JCE provider that supplies the transformation
       
   553      * @return the XMLCipher
       
   554      * @throws XMLEncryptionException
       
   555      */
       
   556     public static XMLCipher getProviderInstance(String provider) throws XMLEncryptionException {
       
   557         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
   558             log.log(java.util.logging.Level.FINE, "Getting XMLCipher with provider");
       
   559         }
       
   560         return new XMLCipher(null, provider, null, null);
       
   561     }
       
   562 
       
   563     /**
       
   564      * Initializes this cipher with a key.
       
   565      * <p>
       
   566      * The cipher is initialized for one of the following four operations:
       
   567      * encryption, decryption, key wrapping or key unwrapping, depending on the
       
   568      * value of opmode.
       
   569      *
       
   570      * For WRAP and ENCRYPT modes, this also initialises the internal
       
   571      * EncryptedKey or EncryptedData (with a CipherValue)
       
   572      * structure that will be used during the ensuing operations.  This
       
   573      * can be obtained (in order to modify KeyInfo elements etc. prior to
       
   574      * finalising the encryption) by calling
       
   575      * {@link #getEncryptedData} or {@link #getEncryptedKey}.
       
   576      *
       
   577      * @param opmode the operation mode of this cipher (this is one of the
       
   578      *   following: ENCRYPT_MODE, DECRYPT_MODE, WRAP_MODE or UNWRAP_MODE)
       
   579      * @param key
       
   580      * @see javax.crypto.Cipher#init(int, java.security.Key)
       
   581      * @throws XMLEncryptionException
       
   582      */
       
   583     public void init(int opmode, Key key) throws XMLEncryptionException {
       
   584         // sanity checks
       
   585         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
   586             log.log(java.util.logging.Level.FINE, "Initializing XMLCipher...");
       
   587         }
       
   588 
       
   589         ek = null;
       
   590         ed = null;
       
   591 
       
   592         switch (opmode) {
       
   593 
       
   594         case ENCRYPT_MODE :
       
   595             if (log.isLoggable(java.util.logging.Level.FINE)) {
       
   596                 log.log(java.util.logging.Level.FINE, "opmode = ENCRYPT_MODE");
       
   597             }
       
   598             ed = createEncryptedData(CipherData.VALUE_TYPE, "NO VALUE YET");
       
   599             break;
       
   600         case DECRYPT_MODE :
       
   601             if (log.isLoggable(java.util.logging.Level.FINE)) {
       
   602                 log.log(java.util.logging.Level.FINE, "opmode = DECRYPT_MODE");
       
   603             }
       
   604             break;
       
   605         case WRAP_MODE :
       
   606             if (log.isLoggable(java.util.logging.Level.FINE)) {
       
   607                 log.log(java.util.logging.Level.FINE, "opmode = WRAP_MODE");
       
   608             }
       
   609             ek = createEncryptedKey(CipherData.VALUE_TYPE, "NO VALUE YET");
       
   610             break;
       
   611         case UNWRAP_MODE :
       
   612             if (log.isLoggable(java.util.logging.Level.FINE)) {
       
   613                 log.log(java.util.logging.Level.FINE, "opmode = UNWRAP_MODE");
       
   614             }
       
   615             break;
       
   616         default :
       
   617             log.log(java.util.logging.Level.SEVERE, "Mode unexpectedly invalid");
       
   618             throw new XMLEncryptionException("Invalid mode in init");
       
   619         }
       
   620 
       
   621         cipherMode = opmode;
       
   622         this.key = key;
       
   623     }
       
   624 
       
   625     /**
       
   626      * Set whether secure validation is enabled or not. The default is false.
       
   627      */
       
   628     public void setSecureValidation(boolean secureValidation) {
       
   629         this.secureValidation = secureValidation;
       
   630     }
       
   631 
       
   632     /**
       
   633      * This method is used to add a custom {@link KeyResolverSpi} to an XMLCipher.
       
   634      * These KeyResolvers are used in KeyInfo objects in DECRYPT and
       
   635      * UNWRAP modes.
       
   636      *
       
   637      * @param keyResolver
       
   638      */
       
   639     public void registerInternalKeyResolver(KeyResolverSpi keyResolver) {
       
   640         if (internalKeyResolvers == null) {
       
   641             internalKeyResolvers = new ArrayList<KeyResolverSpi>();
       
   642         }
       
   643         internalKeyResolvers.add(keyResolver);
       
   644     }
       
   645 
       
   646     /**
       
   647      * Get the EncryptedData being built
       
   648      * <p>
       
   649      * Returns the EncryptedData being built during an ENCRYPT operation.
       
   650      * This can then be used by applications to add KeyInfo elements and
       
   651      * set other parameters.
       
   652      *
       
   653      * @return The EncryptedData being built
       
   654      */
       
   655     public EncryptedData getEncryptedData() {
       
   656         // Sanity checks
       
   657         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
   658             log.log(java.util.logging.Level.FINE, "Returning EncryptedData");
       
   659         }
       
   660         return ed;
       
   661     }
       
   662 
       
   663     /**
       
   664      * Get the EncryptedData being build
       
   665      *
       
   666      * Returns the EncryptedData being built during an ENCRYPT operation.
       
   667      * This can then be used by applications to add KeyInfo elements and
       
   668      * set other parameters.
       
   669      *
       
   670      * @return The EncryptedData being built
       
   671      */
       
   672     public EncryptedKey getEncryptedKey() {
       
   673         // Sanity checks
       
   674         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
   675             log.log(java.util.logging.Level.FINE, "Returning EncryptedKey");
       
   676         }
       
   677         return ek;
       
   678     }
       
   679 
       
   680     /**
       
   681      * Set a Key Encryption Key.
       
   682      * <p>
       
   683      * The Key Encryption Key (KEK) is used for encrypting/decrypting
       
   684      * EncryptedKey elements.  By setting this separately, the XMLCipher
       
   685      * class can know whether a key applies to the data part or wrapped key
       
   686      * part of an encrypted object.
       
   687      *
       
   688      * @param kek The key to use for de/encrypting key data
       
   689      */
       
   690 
       
   691     public void setKEK(Key kek) {
       
   692         this.kek = kek;
       
   693     }
       
   694 
       
   695     /**
       
   696      * Martial an EncryptedData
       
   697      *
       
   698      * Takes an EncryptedData object and returns a DOM Element that
       
   699      * represents the appropriate <code>EncryptedData</code>
       
   700      * <p>
       
   701      * <b>Note:</b> This should only be used in cases where the context
       
   702      * document has been passed in via a call to doFinal.
       
   703      *
       
   704      * @param encryptedData EncryptedData object to martial
       
   705      * @return the DOM <code>Element</code> representing the passed in
       
   706      * object
       
   707      */
       
   708     public Element martial(EncryptedData encryptedData) {
       
   709         return factory.toElement(encryptedData);
       
   710     }
       
   711 
       
   712     /**
       
   713      * Martial an EncryptedData
       
   714      *
       
   715      * Takes an EncryptedData object and returns a DOM Element that
       
   716      * represents the appropriate <code>EncryptedData</code>
       
   717      *
       
   718      * @param context The document that will own the returned nodes
       
   719      * @param encryptedData EncryptedData object to martial
       
   720      * @return the DOM <code>Element</code> representing the passed in
       
   721      * object
       
   722      */
       
   723     public Element martial(Document context, EncryptedData encryptedData) {
       
   724         contextDocument = context;
       
   725         return factory.toElement(encryptedData);
       
   726     }
       
   727 
       
   728     /**
       
   729      * Martial an EncryptedKey
       
   730      *
       
   731      * Takes an EncryptedKey object and returns a DOM Element that
       
   732      * represents the appropriate <code>EncryptedKey</code>
       
   733      *
       
   734      * <p>
       
   735      * <b>Note:</b> This should only be used in cases where the context
       
   736      * document has been passed in via a call to doFinal.
       
   737      *
       
   738      * @param encryptedKey EncryptedKey object to martial
       
   739      * @return the DOM <code>Element</code> representing the passed in
       
   740      * object
       
   741      */
       
   742     public Element martial(EncryptedKey encryptedKey) {
       
   743         return factory.toElement(encryptedKey);
       
   744     }
       
   745 
       
   746     /**
       
   747      * Martial an EncryptedKey
       
   748      *
       
   749      * Takes an EncryptedKey object and returns a DOM Element that
       
   750      * represents the appropriate <code>EncryptedKey</code>
       
   751      *
       
   752      * @param context The document that will own the created nodes
       
   753      * @param encryptedKey EncryptedKey object to martial
       
   754      * @return the DOM <code>Element</code> representing the passed in
       
   755      * object
       
   756      */
       
   757     public Element martial(Document context, EncryptedKey encryptedKey) {
       
   758         contextDocument = context;
       
   759         return factory.toElement(encryptedKey);
       
   760     }
       
   761 
       
   762     /**
       
   763      * Martial a ReferenceList
       
   764      *
       
   765      * Takes a ReferenceList object and returns a DOM Element that
       
   766      * represents the appropriate <code>ReferenceList</code>
       
   767      *
       
   768      * <p>
       
   769      * <b>Note:</b> This should only be used in cases where the context
       
   770      * document has been passed in via a call to doFinal.
       
   771      *
       
   772      * @param referenceList ReferenceList object to martial
       
   773      * @return the DOM <code>Element</code> representing the passed in
       
   774      * object
       
   775      */
       
   776     public Element martial(ReferenceList referenceList) {
       
   777         return factory.toElement(referenceList);
       
   778     }
       
   779 
       
   780     /**
       
   781      * Martial a ReferenceList
       
   782      *
       
   783      * Takes a ReferenceList object and returns a DOM Element that
       
   784      * represents the appropriate <code>ReferenceList</code>
       
   785      *
       
   786      * @param context The document that will own the created nodes
       
   787      * @param referenceList ReferenceList object to martial
       
   788      * @return the DOM <code>Element</code> representing the passed in
       
   789      * object
       
   790      */
       
   791     public Element martial(Document context, ReferenceList referenceList) {
       
   792         contextDocument = context;
       
   793         return factory.toElement(referenceList);
       
   794     }
       
   795 
       
   796     /**
       
   797      * Encrypts an <code>Element</code> and replaces it with its encrypted
       
   798      * counterpart in the context <code>Document</code>, that is, the
       
   799      * <code>Document</code> specified when one calls
       
   800      * {@link #getInstance(String) getInstance}.
       
   801      *
       
   802      * @param element the <code>Element</code> to encrypt.
       
   803      * @return the context <code>Document</code> with the encrypted
       
   804      *   <code>Element</code> having replaced the source <code>Element</code>.
       
   805      *  @throws Exception
       
   806      */
       
   807     private Document encryptElement(Element element) throws Exception{
       
   808         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
   809             log.log(java.util.logging.Level.FINE, "Encrypting element...");
       
   810         }
       
   811         if (null == element) {
       
   812             log.log(java.util.logging.Level.SEVERE, "Element unexpectedly null...");
       
   813         }
       
   814         if (cipherMode != ENCRYPT_MODE && log.isLoggable(java.util.logging.Level.FINE)) {
       
   815             log.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in ENCRYPT_MODE...");
       
   816         }
       
   817 
       
   818         if (algorithm == null) {
       
   819             throw new XMLEncryptionException("XMLCipher instance without transformation specified");
       
   820         }
       
   821         encryptData(contextDocument, element, false);
       
   822 
       
   823         Element encryptedElement = factory.toElement(ed);
       
   824 
       
   825         Node sourceParent = element.getParentNode();
       
   826         sourceParent.replaceChild(encryptedElement, element);
       
   827 
       
   828         return contextDocument;
       
   829     }
       
   830 
       
   831     /**
       
   832      * Encrypts a <code>NodeList</code> (the contents of an
       
   833      * <code>Element</code>) and replaces its parent <code>Element</code>'s
       
   834      * content with this the resulting <code>EncryptedType</code> within the
       
   835      * context <code>Document</code>, that is, the <code>Document</code>
       
   836      * specified when one calls
       
   837      * {@link #getInstance(String) getInstance}.
       
   838      *
       
   839      * @param element the <code>NodeList</code> to encrypt.
       
   840      * @return the context <code>Document</code> with the encrypted
       
   841      *   <code>NodeList</code> having replaced the content of the source
       
   842      *   <code>Element</code>.
       
   843      * @throws Exception
       
   844      */
       
   845     private Document encryptElementContent(Element element) throws /* XMLEncryption */Exception {
       
   846         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
   847             log.log(java.util.logging.Level.FINE, "Encrypting element content...");
       
   848         }
       
   849         if (null == element) {
       
   850             log.log(java.util.logging.Level.SEVERE, "Element unexpectedly null...");
       
   851         }
       
   852         if (cipherMode != ENCRYPT_MODE && log.isLoggable(java.util.logging.Level.FINE)) {
       
   853             log.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in ENCRYPT_MODE...");
       
   854         }
       
   855 
       
   856         if (algorithm == null) {
       
   857             throw new XMLEncryptionException("XMLCipher instance without transformation specified");
       
   858         }
       
   859         encryptData(contextDocument, element, true);
       
   860 
       
   861         Element encryptedElement = factory.toElement(ed);
       
   862 
       
   863         removeContent(element);
       
   864         element.appendChild(encryptedElement);
       
   865 
       
   866         return contextDocument;
       
   867     }
       
   868 
       
   869     /**
       
   870      * Process a DOM <code>Document</code> node. The processing depends on the
       
   871      * initialization parameters of {@link #init(int, Key) init()}.
       
   872      *
       
   873      * @param context the context <code>Document</code>.
       
   874      * @param source the <code>Document</code> to be encrypted or decrypted.
       
   875      * @return the processed <code>Document</code>.
       
   876      * @throws Exception to indicate any exceptional conditions.
       
   877      */
       
   878     public Document doFinal(Document context, Document source) throws /* XMLEncryption */Exception {
       
   879         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
   880             log.log(java.util.logging.Level.FINE, "Processing source document...");
       
   881         }
       
   882         if (null == context) {
       
   883             log.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null...");
       
   884         }
       
   885         if (null == source) {
       
   886             log.log(java.util.logging.Level.SEVERE, "Source document unexpectedly null...");
       
   887         }
       
   888 
       
   889         contextDocument = context;
       
   890 
       
   891         Document result = null;
       
   892 
       
   893         switch (cipherMode) {
       
   894         case DECRYPT_MODE:
       
   895             result = decryptElement(source.getDocumentElement());
       
   896             break;
       
   897         case ENCRYPT_MODE:
       
   898             result = encryptElement(source.getDocumentElement());
       
   899             break;
       
   900         case UNWRAP_MODE:
       
   901         case WRAP_MODE:
       
   902             break;
       
   903         default:
       
   904             throw new XMLEncryptionException("empty", new IllegalStateException());
       
   905         }
       
   906 
       
   907         return result;
       
   908     }
       
   909 
       
   910     /**
       
   911      * Process a DOM <code>Element</code> node. The processing depends on the
       
   912      * initialization parameters of {@link #init(int, Key) init()}.
       
   913      *
       
   914      * @param context the context <code>Document</code>.
       
   915      * @param element the <code>Element</code> to be encrypted.
       
   916      * @return the processed <code>Document</code>.
       
   917      * @throws Exception to indicate any exceptional conditions.
       
   918      */
       
   919     public Document doFinal(Document context, Element element) throws /* XMLEncryption */Exception {
       
   920         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
   921             log.log(java.util.logging.Level.FINE, "Processing source element...");
       
   922         }
       
   923         if (null == context) {
       
   924             log.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null...");
       
   925         }
       
   926         if (null == element) {
       
   927             log.log(java.util.logging.Level.SEVERE, "Source element unexpectedly null...");
       
   928         }
       
   929 
       
   930         contextDocument = context;
       
   931 
       
   932         Document result = null;
       
   933 
       
   934         switch (cipherMode) {
       
   935         case DECRYPT_MODE:
       
   936             result = decryptElement(element);
       
   937             break;
       
   938         case ENCRYPT_MODE:
       
   939             result = encryptElement(element);
       
   940             break;
       
   941         case UNWRAP_MODE:
       
   942         case WRAP_MODE:
       
   943             break;
       
   944         default:
       
   945             throw new XMLEncryptionException("empty", new IllegalStateException());
       
   946         }
       
   947 
       
   948         return result;
       
   949     }
       
   950 
       
   951     /**
       
   952      * Process the contents of a DOM <code>Element</code> node. The processing
       
   953      * depends on the initialization parameters of
       
   954      * {@link #init(int, Key) init()}.
       
   955      *
       
   956      * @param context the context <code>Document</code>.
       
   957      * @param element the <code>Element</code> which contents is to be
       
   958      *   encrypted.
       
   959      * @param content
       
   960      * @return the processed <code>Document</code>.
       
   961      * @throws Exception to indicate any exceptional conditions.
       
   962      */
       
   963     public Document doFinal(Document context, Element element, boolean content)
       
   964         throws /* XMLEncryption*/ Exception {
       
   965         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
   966             log.log(java.util.logging.Level.FINE, "Processing source element...");
       
   967         }
       
   968         if (null == context) {
       
   969             log.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null...");
       
   970         }
       
   971         if (null == element) {
       
   972             log.log(java.util.logging.Level.SEVERE, "Source element unexpectedly null...");
       
   973         }
       
   974 
       
   975         contextDocument = context;
       
   976 
       
   977         Document result = null;
       
   978 
       
   979         switch (cipherMode) {
       
   980         case DECRYPT_MODE:
       
   981             if (content) {
       
   982                 result = decryptElementContent(element);
       
   983             } else {
       
   984                 result = decryptElement(element);
       
   985             }
       
   986             break;
       
   987         case ENCRYPT_MODE:
       
   988             if (content) {
       
   989                 result = encryptElementContent(element);
       
   990             } else {
       
   991                 result = encryptElement(element);
       
   992             }
       
   993             break;
       
   994         case UNWRAP_MODE:
       
   995         case WRAP_MODE:
       
   996             break;
       
   997         default:
       
   998             throw new XMLEncryptionException("empty", new IllegalStateException());
       
   999         }
       
  1000 
       
  1001         return result;
       
  1002     }
       
  1003 
       
  1004     /**
       
  1005      * Returns an <code>EncryptedData</code> interface. Use this operation if
       
  1006      * you want to have full control over the contents of the
       
  1007      * <code>EncryptedData</code> structure.
       
  1008      *
       
  1009      * This does not change the source document in any way.
       
  1010      *
       
  1011      * @param context the context <code>Document</code>.
       
  1012      * @param element the <code>Element</code> that will be encrypted.
       
  1013      * @return the <code>EncryptedData</code>
       
  1014      * @throws Exception
       
  1015      */
       
  1016     public EncryptedData encryptData(Document context, Element element) throws
       
  1017         /* XMLEncryption */Exception {
       
  1018         return encryptData(context, element, false);
       
  1019     }
       
  1020 
       
  1021     /**
       
  1022      * Returns an <code>EncryptedData</code> interface. Use this operation if
       
  1023      * you want to have full control over the serialization of the element
       
  1024      * or element content.
       
  1025      *
       
  1026      * This does not change the source document in any way.
       
  1027      *
       
  1028      * @param context the context <code>Document</code>.
       
  1029      * @param type a URI identifying type information about the plaintext form
       
  1030      *    of the encrypted content (may be <code>null</code>)
       
  1031      * @param serializedData the serialized data
       
  1032      * @return the <code>EncryptedData</code>
       
  1033      * @throws Exception
       
  1034      */
       
  1035     public EncryptedData encryptData(
       
  1036         Document context, String type, InputStream serializedData
       
  1037     ) throws Exception {
       
  1038         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
  1039             log.log(java.util.logging.Level.FINE, "Encrypting element...");
       
  1040         }
       
  1041         if (null == context) {
       
  1042             log.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null...");
       
  1043         }
       
  1044         if (null == serializedData) {
       
  1045             log.log(java.util.logging.Level.SEVERE, "Serialized data unexpectedly null...");
       
  1046         }
       
  1047         if (cipherMode != ENCRYPT_MODE && log.isLoggable(java.util.logging.Level.FINE)) {
       
  1048             log.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in ENCRYPT_MODE...");
       
  1049         }
       
  1050 
       
  1051         return encryptData(context, null, type, serializedData);
       
  1052     }
       
  1053 
       
  1054     /**
       
  1055      * Returns an <code>EncryptedData</code> interface. Use this operation if
       
  1056      * you want to have full control over the contents of the
       
  1057      * <code>EncryptedData</code> structure.
       
  1058      *
       
  1059      * This does not change the source document in any way.
       
  1060      *
       
  1061      * @param context the context <code>Document</code>.
       
  1062      * @param element the <code>Element</code> that will be encrypted.
       
  1063      * @param contentMode <code>true</code> to encrypt element's content only,
       
  1064      *    <code>false</code> otherwise
       
  1065      * @return the <code>EncryptedData</code>
       
  1066      * @throws Exception
       
  1067      */
       
  1068     public EncryptedData encryptData(
       
  1069         Document context, Element element, boolean contentMode
       
  1070     ) throws /* XMLEncryption */ Exception {
       
  1071         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
  1072             log.log(java.util.logging.Level.FINE, "Encrypting element...");
       
  1073         }
       
  1074         if (null == context) {
       
  1075             log.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null...");
       
  1076         }
       
  1077         if (null == element) {
       
  1078             log.log(java.util.logging.Level.SEVERE, "Element unexpectedly null...");
       
  1079         }
       
  1080         if (cipherMode != ENCRYPT_MODE && log.isLoggable(java.util.logging.Level.FINE)) {
       
  1081             log.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in ENCRYPT_MODE...");
       
  1082         }
       
  1083 
       
  1084         if (contentMode) {
       
  1085             return encryptData(context, element, EncryptionConstants.TYPE_CONTENT, null);
       
  1086         } else {
       
  1087             return encryptData(context, element, EncryptionConstants.TYPE_ELEMENT, null);
       
  1088         }
       
  1089     }
       
  1090 
       
  1091     private EncryptedData encryptData(
       
  1092         Document context, Element element, String type, InputStream serializedData
       
  1093     ) throws /* XMLEncryption */ Exception {
       
  1094         contextDocument = context;
       
  1095 
       
  1096         if (algorithm == null) {
       
  1097             throw new XMLEncryptionException("XMLCipher instance without transformation specified");
       
  1098         }
       
  1099 
       
  1100         byte[] serializedOctets = null;
       
  1101         if (serializedData == null) {
       
  1102             if (type.equals(EncryptionConstants.TYPE_CONTENT)) {
       
  1103                 NodeList children = element.getChildNodes();
       
  1104                 if (null != children) {
       
  1105                     serializedOctets = serializer.serializeToByteArray(children);
       
  1106                 } else {
       
  1107                     Object exArgs[] = { "Element has no content." };
       
  1108                     throw new XMLEncryptionException("empty", exArgs);
       
  1109                 }
       
  1110             } else {
       
  1111                 serializedOctets = serializer.serializeToByteArray(element);
       
  1112             }
       
  1113             if (log.isLoggable(java.util.logging.Level.FINE)) {
       
  1114                 log.log(java.util.logging.Level.FINE, "Serialized octets:\n" + new String(serializedOctets, "UTF-8"));
       
  1115             }
       
  1116         }
       
  1117 
       
  1118         byte[] encryptedBytes = null;
       
  1119 
       
  1120         // Now create the working cipher if none was created already
       
  1121         Cipher c;
       
  1122         if (contextCipher == null) {
       
  1123             c = constructCipher(algorithm, null);
       
  1124         } else {
       
  1125             c = contextCipher;
       
  1126         }
       
  1127         // Now perform the encryption
       
  1128 
       
  1129         try {
       
  1130             // The Spec mandates a 96-bit IV for GCM algorithms
       
  1131             if (AES_128_GCM.equals(algorithm) || AES_192_GCM.equals(algorithm)
       
  1132                 || AES_256_GCM.equals(algorithm)) {
       
  1133                 if (random == null) {
       
  1134                     random = SecureRandom.getInstance("SHA1PRNG");
       
  1135                 }
       
  1136                 byte[] temp = new byte[12];
       
  1137                 random.nextBytes(temp);
       
  1138                 IvParameterSpec paramSpec = new IvParameterSpec(temp);
       
  1139                 c.init(cipherMode, key, paramSpec);
       
  1140             } else {
       
  1141                 c.init(cipherMode, key);
       
  1142             }
       
  1143         } catch (InvalidKeyException ike) {
       
  1144             throw new XMLEncryptionException("empty", ike);
       
  1145         } catch (NoSuchAlgorithmException ex) {
       
  1146             throw new XMLEncryptionException("empty", ex);
       
  1147         }
       
  1148 
       
  1149         try {
       
  1150             if (serializedData != null) {
       
  1151                 int numBytes;
       
  1152                 byte[] buf = new byte[8192];
       
  1153                 ByteArrayOutputStream baos = new ByteArrayOutputStream();
       
  1154                 while ((numBytes = serializedData.read(buf)) != -1) {
       
  1155                     byte[] data = c.update(buf, 0, numBytes);
       
  1156                     baos.write(data);
       
  1157                 }
       
  1158                 baos.write(c.doFinal());
       
  1159                 encryptedBytes = baos.toByteArray();
       
  1160             } else {
       
  1161                 encryptedBytes = c.doFinal(serializedOctets);
       
  1162                 if (log.isLoggable(java.util.logging.Level.FINE)) {
       
  1163                     log.log(java.util.logging.Level.FINE, "Expected cipher.outputSize = " +
       
  1164                         Integer.toString(c.getOutputSize(serializedOctets.length)));
       
  1165                 }
       
  1166             }
       
  1167             if (log.isLoggable(java.util.logging.Level.FINE)) {
       
  1168                 log.log(java.util.logging.Level.FINE, "Actual cipher.outputSize = "
       
  1169                              + Integer.toString(encryptedBytes.length));
       
  1170             }
       
  1171         } catch (IllegalStateException ise) {
       
  1172             throw new XMLEncryptionException("empty", ise);
       
  1173         } catch (IllegalBlockSizeException ibse) {
       
  1174             throw new XMLEncryptionException("empty", ibse);
       
  1175         } catch (BadPaddingException bpe) {
       
  1176             throw new XMLEncryptionException("empty", bpe);
       
  1177         } catch (UnsupportedEncodingException uee) {
       
  1178             throw new XMLEncryptionException("empty", uee);
       
  1179         }
       
  1180 
       
  1181         // Now build up to a properly XML Encryption encoded octet stream
       
  1182         // IvParameterSpec iv;
       
  1183         byte[] iv = c.getIV();
       
  1184         byte[] finalEncryptedBytes = new byte[iv.length + encryptedBytes.length];
       
  1185         System.arraycopy(iv, 0, finalEncryptedBytes, 0, iv.length);
       
  1186         System.arraycopy(encryptedBytes, 0, finalEncryptedBytes, iv.length, encryptedBytes.length);
       
  1187         String base64EncodedEncryptedOctets = Base64.encode(finalEncryptedBytes);
       
  1188 
       
  1189         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
  1190             log.log(java.util.logging.Level.FINE, "Encrypted octets:\n" + base64EncodedEncryptedOctets);
       
  1191             log.log(java.util.logging.Level.FINE, "Encrypted octets length = " + base64EncodedEncryptedOctets.length());
       
  1192         }
       
  1193 
       
  1194         try {
       
  1195             CipherData cd = ed.getCipherData();
       
  1196             CipherValue cv = cd.getCipherValue();
       
  1197             // cv.setValue(base64EncodedEncryptedOctets.getBytes());
       
  1198             cv.setValue(base64EncodedEncryptedOctets);
       
  1199 
       
  1200             if (type != null) {
       
  1201                 ed.setType(new URI(type).toString());
       
  1202             }
       
  1203             EncryptionMethod method =
       
  1204                 factory.newEncryptionMethod(new URI(algorithm).toString());
       
  1205             method.setDigestAlgorithm(digestAlg);
       
  1206             ed.setEncryptionMethod(method);
       
  1207         } catch (URISyntaxException ex) {
       
  1208             throw new XMLEncryptionException("empty", ex);
       
  1209         }
       
  1210         return ed;
       
  1211     }
       
  1212 
       
  1213     /**
       
  1214      * Returns an <code>EncryptedData</code> interface. Use this operation if
       
  1215      * you want to load an <code>EncryptedData</code> structure from a DOM
       
  1216      * structure and manipulate the contents.
       
  1217      *
       
  1218      * @param context the context <code>Document</code>.
       
  1219      * @param element the <code>Element</code> that will be loaded
       
  1220      * @throws XMLEncryptionException
       
  1221      * @return the <code>EncryptedData</code>
       
  1222      */
       
  1223     public EncryptedData loadEncryptedData(Document context, Element element)
       
  1224         throws XMLEncryptionException {
       
  1225         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
  1226             log.log(java.util.logging.Level.FINE, "Loading encrypted element...");
       
  1227         }
       
  1228         if (null == context) {
       
  1229             throw new NullPointerException("Context document unexpectedly null...");
       
  1230         }
       
  1231         if (null == element) {
       
  1232             throw new NullPointerException("Element unexpectedly null...");
       
  1233         }
       
  1234         if (cipherMode != DECRYPT_MODE) {
       
  1235             throw new XMLEncryptionException("XMLCipher unexpectedly not in DECRYPT_MODE...");
       
  1236         }
       
  1237 
       
  1238         contextDocument = context;
       
  1239         ed = factory.newEncryptedData(element);
       
  1240 
       
  1241         return ed;
       
  1242     }
       
  1243 
       
  1244     /**
       
  1245      * Returns an <code>EncryptedKey</code> interface. Use this operation if
       
  1246      * you want to load an <code>EncryptedKey</code> structure from a DOM
       
  1247      * structure and manipulate the contents.
       
  1248      *
       
  1249      * @param context the context <code>Document</code>.
       
  1250      * @param element the <code>Element</code> that will be loaded
       
  1251      * @return the <code>EncryptedKey</code>
       
  1252      * @throws XMLEncryptionException
       
  1253      */
       
  1254     public EncryptedKey loadEncryptedKey(Document context, Element element)
       
  1255         throws XMLEncryptionException {
       
  1256         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
  1257             log.log(java.util.logging.Level.FINE, "Loading encrypted key...");
       
  1258         }
       
  1259         if (null == context) {
       
  1260             throw new NullPointerException("Context document unexpectedly null...");
       
  1261         }
       
  1262         if (null == element) {
       
  1263             throw new NullPointerException("Element unexpectedly null...");
       
  1264         }
       
  1265         if (cipherMode != UNWRAP_MODE && cipherMode != DECRYPT_MODE) {
       
  1266             throw new XMLEncryptionException(
       
  1267                 "XMLCipher unexpectedly not in UNWRAP_MODE or DECRYPT_MODE..."
       
  1268             );
       
  1269         }
       
  1270 
       
  1271         contextDocument = context;
       
  1272         ek = factory.newEncryptedKey(element);
       
  1273         return ek;
       
  1274     }
       
  1275 
       
  1276     /**
       
  1277      * Returns an <code>EncryptedKey</code> interface. Use this operation if
       
  1278      * you want to load an <code>EncryptedKey</code> structure from a DOM
       
  1279      * structure and manipulate the contents.
       
  1280      *
       
  1281      * Assumes that the context document is the document that owns the element
       
  1282      *
       
  1283      * @param element the <code>Element</code> that will be loaded
       
  1284      * @return the <code>EncryptedKey</code>
       
  1285      * @throws XMLEncryptionException
       
  1286      */
       
  1287     public EncryptedKey loadEncryptedKey(Element element) throws XMLEncryptionException {
       
  1288         return loadEncryptedKey(element.getOwnerDocument(), element);
       
  1289     }
       
  1290 
       
  1291     /**
       
  1292      * Encrypts a key to an EncryptedKey structure
       
  1293      *
       
  1294      * @param doc the Context document that will be used to general DOM
       
  1295      * @param key Key to encrypt (will use previously set KEK to
       
  1296      * perform encryption
       
  1297      * @return the <code>EncryptedKey</code>
       
  1298      * @throws XMLEncryptionException
       
  1299      */
       
  1300     public EncryptedKey encryptKey(Document doc, Key key) throws XMLEncryptionException {
       
  1301         return encryptKey(doc, key, null, null);
       
  1302     }
       
  1303 
       
  1304     /**
       
  1305      * Encrypts a key to an EncryptedKey structure
       
  1306      *
       
  1307      * @param doc the Context document that will be used to general DOM
       
  1308      * @param key Key to encrypt (will use previously set KEK to
       
  1309      * perform encryption
       
  1310      * @param mgfAlgorithm The xenc11 MGF Algorithm to use
       
  1311      * @param oaepParams The OAEPParams to use
       
  1312      * @return the <code>EncryptedKey</code>
       
  1313      * @throws XMLEncryptionException
       
  1314      */
       
  1315     public EncryptedKey encryptKey(
       
  1316         Document doc,
       
  1317         Key key,
       
  1318         String mgfAlgorithm,
       
  1319         byte[] oaepParams
       
  1320     ) throws XMLEncryptionException {
       
  1321         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
  1322             log.log(java.util.logging.Level.FINE, "Encrypting key ...");
       
  1323         }
       
  1324 
       
  1325         if (null == key) {
       
  1326             log.log(java.util.logging.Level.SEVERE, "Key unexpectedly null...");
       
  1327         }
       
  1328         if (cipherMode != WRAP_MODE) {
       
  1329             log.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in WRAP_MODE...");
       
  1330         }
       
  1331         if (algorithm == null) {
       
  1332             throw new XMLEncryptionException("XMLCipher instance without transformation specified");
       
  1333         }
       
  1334 
       
  1335         contextDocument = doc;
       
  1336 
       
  1337         byte[] encryptedBytes = null;
       
  1338         Cipher c;
       
  1339 
       
  1340         if (contextCipher == null) {
       
  1341             // Now create the working cipher
       
  1342             c = constructCipher(algorithm, null);
       
  1343         } else {
       
  1344             c = contextCipher;
       
  1345         }
       
  1346         // Now perform the encryption
       
  1347 
       
  1348         try {
       
  1349             // Should internally generate an IV
       
  1350             // todo - allow user to set an IV
       
  1351             OAEPParameterSpec oaepParameters =
       
  1352                 constructOAEPParameters(
       
  1353                     algorithm, digestAlg, mgfAlgorithm, oaepParams
       
  1354                 );
       
  1355             if (oaepParameters == null) {
       
  1356                 c.init(Cipher.WRAP_MODE, this.key);
       
  1357             } else {
       
  1358                 c.init(Cipher.WRAP_MODE, this.key, oaepParameters);
       
  1359             }
       
  1360             encryptedBytes = c.wrap(key);
       
  1361         } catch (InvalidKeyException ike) {
       
  1362             throw new XMLEncryptionException("empty", ike);
       
  1363         } catch (IllegalBlockSizeException ibse) {
       
  1364             throw new XMLEncryptionException("empty", ibse);
       
  1365         } catch (InvalidAlgorithmParameterException e) {
       
  1366             throw new XMLEncryptionException("empty", e);
       
  1367         }
       
  1368 
       
  1369         String base64EncodedEncryptedOctets = Base64.encode(encryptedBytes);
       
  1370         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
  1371             log.log(java.util.logging.Level.FINE, "Encrypted key octets:\n" + base64EncodedEncryptedOctets);
       
  1372             log.log(java.util.logging.Level.FINE, "Encrypted key octets length = " + base64EncodedEncryptedOctets.length());
       
  1373         }
       
  1374 
       
  1375         CipherValue cv = ek.getCipherData().getCipherValue();
       
  1376         cv.setValue(base64EncodedEncryptedOctets);
       
  1377 
       
  1378         try {
       
  1379             EncryptionMethod method = factory.newEncryptionMethod(new URI(algorithm).toString());
       
  1380             method.setDigestAlgorithm(digestAlg);
       
  1381             method.setMGFAlgorithm(mgfAlgorithm);
       
  1382             method.setOAEPparams(oaepParams);
       
  1383             ek.setEncryptionMethod(method);
       
  1384         } catch (URISyntaxException ex) {
       
  1385             throw new XMLEncryptionException("empty", ex);
       
  1386         }
       
  1387         return ek;
       
  1388     }
       
  1389 
       
  1390     /**
       
  1391      * Decrypt a key from a passed in EncryptedKey structure
       
  1392      *
       
  1393      * @param encryptedKey Previously loaded EncryptedKey that needs
       
  1394      * to be decrypted.
       
  1395      * @param algorithm Algorithm for the decryption
       
  1396      * @return a key corresponding to the given type
       
  1397      * @throws XMLEncryptionException
       
  1398      */
       
  1399     public Key decryptKey(EncryptedKey encryptedKey, String algorithm)
       
  1400         throws XMLEncryptionException {
       
  1401         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
  1402             log.log(java.util.logging.Level.FINE, "Decrypting key from previously loaded EncryptedKey...");
       
  1403         }
       
  1404 
       
  1405         if (cipherMode != UNWRAP_MODE && log.isLoggable(java.util.logging.Level.FINE)) {
       
  1406             log.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in UNWRAP_MODE...");
       
  1407         }
       
  1408 
       
  1409         if (algorithm == null) {
       
  1410             throw new XMLEncryptionException("Cannot decrypt a key without knowing the algorithm");
       
  1411         }
       
  1412 
       
  1413         if (key == null) {
       
  1414             if (log.isLoggable(java.util.logging.Level.FINE)) {
       
  1415                 log.log(java.util.logging.Level.FINE, "Trying to find a KEK via key resolvers");
       
  1416             }
       
  1417 
       
  1418             KeyInfo ki = encryptedKey.getKeyInfo();
       
  1419             if (ki != null) {
       
  1420                 ki.setSecureValidation(secureValidation);
       
  1421                 try {
       
  1422                     String keyWrapAlg = encryptedKey.getEncryptionMethod().getAlgorithm();
       
  1423                     String keyType = JCEMapper.getJCEKeyAlgorithmFromURI(keyWrapAlg);
       
  1424                     if ("RSA".equals(keyType)) {
       
  1425                         key = ki.getPrivateKey();
       
  1426                     } else {
       
  1427                         key = ki.getSecretKey();
       
  1428                     }
       
  1429                 }
       
  1430                 catch (Exception e) {
       
  1431                     if (log.isLoggable(java.util.logging.Level.FINE)) {
       
  1432                         log.log(java.util.logging.Level.FINE, e.getMessage(), e);
       
  1433                     }
       
  1434                 }
       
  1435             }
       
  1436             if (key == null) {
       
  1437                 log.log(java.util.logging.Level.SEVERE, "XMLCipher::decryptKey called without a KEK and cannot resolve");
       
  1438                 throw new XMLEncryptionException("Unable to decrypt without a KEK");
       
  1439             }
       
  1440         }
       
  1441 
       
  1442         // Obtain the encrypted octets
       
  1443         XMLCipherInput cipherInput = new XMLCipherInput(encryptedKey);
       
  1444         cipherInput.setSecureValidation(secureValidation);
       
  1445         byte[] encryptedBytes = cipherInput.getBytes();
       
  1446 
       
  1447         String jceKeyAlgorithm = JCEMapper.getJCEKeyAlgorithmFromURI(algorithm);
       
  1448         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
  1449             log.log(java.util.logging.Level.FINE, "JCE Key Algorithm: " + jceKeyAlgorithm);
       
  1450         }
       
  1451 
       
  1452         Cipher c;
       
  1453         if (contextCipher == null) {
       
  1454             // Now create the working cipher
       
  1455             c =
       
  1456                 constructCipher(
       
  1457                     encryptedKey.getEncryptionMethod().getAlgorithm(),
       
  1458                     encryptedKey.getEncryptionMethod().getDigestAlgorithm()
       
  1459                 );
       
  1460         } else {
       
  1461             c = contextCipher;
       
  1462         }
       
  1463 
       
  1464         Key ret;
       
  1465 
       
  1466         try {
       
  1467             EncryptionMethod encMethod = encryptedKey.getEncryptionMethod();
       
  1468             OAEPParameterSpec oaepParameters =
       
  1469                 constructOAEPParameters(
       
  1470                     encMethod.getAlgorithm(), encMethod.getDigestAlgorithm(),
       
  1471                     encMethod.getMGFAlgorithm(), encMethod.getOAEPparams()
       
  1472                 );
       
  1473             if (oaepParameters == null) {
       
  1474                 c.init(Cipher.UNWRAP_MODE, key);
       
  1475             } else {
       
  1476                 c.init(Cipher.UNWRAP_MODE, key, oaepParameters);
       
  1477             }
       
  1478             ret = c.unwrap(encryptedBytes, jceKeyAlgorithm, Cipher.SECRET_KEY);
       
  1479         } catch (InvalidKeyException ike) {
       
  1480             throw new XMLEncryptionException("empty", ike);
       
  1481         } catch (NoSuchAlgorithmException nsae) {
       
  1482             throw new XMLEncryptionException("empty", nsae);
       
  1483         } catch (InvalidAlgorithmParameterException e) {
       
  1484             throw new XMLEncryptionException("empty", e);
       
  1485         }
       
  1486         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
  1487             log.log(java.util.logging.Level.FINE, "Decryption of key type " + algorithm + " OK");
       
  1488         }
       
  1489 
       
  1490         return ret;
       
  1491     }
       
  1492 
       
  1493     /**
       
  1494      * Construct an OAEPParameterSpec object from the given parameters
       
  1495      */
       
  1496     private OAEPParameterSpec constructOAEPParameters(
       
  1497         String encryptionAlgorithm,
       
  1498         String digestAlgorithm,
       
  1499         String mgfAlgorithm,
       
  1500         byte[] oaepParams
       
  1501     ) {
       
  1502         if (XMLCipher.RSA_OAEP.equals(encryptionAlgorithm)
       
  1503             || XMLCipher.RSA_OAEP_11.equals(encryptionAlgorithm)) {
       
  1504 
       
  1505             String jceDigestAlgorithm = "SHA-1";
       
  1506             if (digestAlgorithm != null) {
       
  1507                 jceDigestAlgorithm = JCEMapper.translateURItoJCEID(digestAlgorithm);
       
  1508             }
       
  1509 
       
  1510             PSource.PSpecified pSource = PSource.PSpecified.DEFAULT;
       
  1511             if (oaepParams != null) {
       
  1512                 pSource = new PSource.PSpecified(oaepParams);
       
  1513             }
       
  1514 
       
  1515             MGF1ParameterSpec mgfParameterSpec = new MGF1ParameterSpec("SHA-1");
       
  1516             if (XMLCipher.RSA_OAEP_11.equals(encryptionAlgorithm)) {
       
  1517                 if (EncryptionConstants.MGF1_SHA256.equals(mgfAlgorithm)) {
       
  1518                     mgfParameterSpec = new MGF1ParameterSpec("SHA-256");
       
  1519                 } else if (EncryptionConstants.MGF1_SHA384.equals(mgfAlgorithm)) {
       
  1520                     mgfParameterSpec = new MGF1ParameterSpec("SHA-384");
       
  1521                 } else if (EncryptionConstants.MGF1_SHA512.equals(mgfAlgorithm)) {
       
  1522                     mgfParameterSpec = new MGF1ParameterSpec("SHA-512");
       
  1523                 }
       
  1524             }
       
  1525             return new OAEPParameterSpec(jceDigestAlgorithm, "MGF1", mgfParameterSpec, pSource);
       
  1526         }
       
  1527 
       
  1528         return null;
       
  1529     }
       
  1530 
       
  1531     /**
       
  1532      * Construct a Cipher object
       
  1533      */
       
  1534     private Cipher constructCipher(String algorithm, String digestAlgorithm) throws XMLEncryptionException {
       
  1535         String jceAlgorithm = JCEMapper.translateURItoJCEID(algorithm);
       
  1536         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
  1537             log.log(java.util.logging.Level.FINE, "JCE Algorithm = " + jceAlgorithm);
       
  1538         }
       
  1539 
       
  1540         Cipher c;
       
  1541         try {
       
  1542             if (requestedJCEProvider == null) {
       
  1543                 c = Cipher.getInstance(jceAlgorithm);
       
  1544             } else {
       
  1545                 c = Cipher.getInstance(jceAlgorithm, requestedJCEProvider);
       
  1546             }
       
  1547         } catch (NoSuchAlgorithmException nsae) {
       
  1548             // Check to see if an RSA OAEP MGF-1 with SHA-1 algorithm was requested
       
  1549             // Some JDKs don't support RSA/ECB/OAEPPadding
       
  1550             if (XMLCipher.RSA_OAEP.equals(algorithm)
       
  1551                 && (digestAlgorithm == null
       
  1552                     || MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA1.equals(digestAlgorithm))) {
       
  1553                 try {
       
  1554                     if (requestedJCEProvider == null) {
       
  1555                         c = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
       
  1556                     } else {
       
  1557                         c = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding", requestedJCEProvider);
       
  1558                     }
       
  1559                 } catch (Exception ex) {
       
  1560                     throw new XMLEncryptionException("empty", ex);
       
  1561                 }
       
  1562             } else {
       
  1563                 throw new XMLEncryptionException("empty", nsae);
       
  1564             }
       
  1565         } catch (NoSuchProviderException nspre) {
       
  1566             throw new XMLEncryptionException("empty", nspre);
       
  1567         } catch (NoSuchPaddingException nspae) {
       
  1568             throw new XMLEncryptionException("empty", nspae);
       
  1569         }
       
  1570 
       
  1571         return c;
       
  1572     }
       
  1573 
       
  1574     /**
       
  1575      * Decrypt a key from a passed in EncryptedKey structure.  This version
       
  1576      * is used mainly internally, when  the cipher already has an
       
  1577      * EncryptedData loaded.  The algorithm URI will be read from the
       
  1578      * EncryptedData
       
  1579      *
       
  1580      * @param encryptedKey Previously loaded EncryptedKey that needs
       
  1581      * to be decrypted.
       
  1582      * @return a key corresponding to the given type
       
  1583      * @throws XMLEncryptionException
       
  1584      */
       
  1585     public Key decryptKey(EncryptedKey encryptedKey) throws XMLEncryptionException {
       
  1586         return decryptKey(encryptedKey, ed.getEncryptionMethod().getAlgorithm());
       
  1587     }
       
  1588 
       
  1589     /**
       
  1590      * Removes the contents of a <code>Node</code>.
       
  1591      *
       
  1592      * @param node the <code>Node</code> to clear.
       
  1593      */
       
  1594     private static void removeContent(Node node) {
       
  1595         while (node.hasChildNodes()) {
       
  1596             node.removeChild(node.getFirstChild());
       
  1597         }
       
  1598     }
       
  1599 
       
  1600     /**
       
  1601      * Decrypts <code>EncryptedData</code> in a single-part operation.
       
  1602      *
       
  1603      * @param element the <code>EncryptedData</code> to decrypt.
       
  1604      * @return the <code>Node</code> as a result of the decrypt operation.
       
  1605      * @throws XMLEncryptionException
       
  1606      */
       
  1607     private Document decryptElement(Element element) throws XMLEncryptionException {
       
  1608         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
  1609             log.log(java.util.logging.Level.FINE, "Decrypting element...");
       
  1610         }
       
  1611 
       
  1612         if (cipherMode != DECRYPT_MODE) {
       
  1613             log.log(java.util.logging.Level.SEVERE, "XMLCipher unexpectedly not in DECRYPT_MODE...");
       
  1614         }
       
  1615 
       
  1616         byte[] octets = decryptToByteArray(element);
       
  1617 
       
  1618         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
  1619             log.log(java.util.logging.Level.FINE, "Decrypted octets:\n" + new String(octets));
       
  1620         }
       
  1621 
       
  1622         Node sourceParent = element.getParentNode();
       
  1623         Node decryptedNode = serializer.deserialize(octets, sourceParent);
       
  1624 
       
  1625         // The de-serialiser returns a node whose children we need to take on.
       
  1626         if (sourceParent != null && Node.DOCUMENT_NODE == sourceParent.getNodeType()) {
       
  1627             // If this is a content decryption, this may have problems
       
  1628             contextDocument.removeChild(contextDocument.getDocumentElement());
       
  1629             contextDocument.appendChild(decryptedNode);
       
  1630         } else if (sourceParent != null) {
       
  1631             sourceParent.replaceChild(decryptedNode, element);
       
  1632         }
       
  1633 
       
  1634         return contextDocument;
       
  1635     }
       
  1636 
       
  1637     /**
       
  1638      *
       
  1639      * @param element
       
  1640      * @return the <code>Node</code> as a result of the decrypt operation.
       
  1641      * @throws XMLEncryptionException
       
  1642      */
       
  1643     private Document decryptElementContent(Element element) throws XMLEncryptionException {
       
  1644         Element e =
       
  1645             (Element) element.getElementsByTagNameNS(
       
  1646                 EncryptionConstants.EncryptionSpecNS,
       
  1647                 EncryptionConstants._TAG_ENCRYPTEDDATA
       
  1648             ).item(0);
       
  1649 
       
  1650         if (null == e) {
       
  1651             throw new XMLEncryptionException("No EncryptedData child element.");
       
  1652         }
       
  1653 
       
  1654         return decryptElement(e);
       
  1655     }
       
  1656 
       
  1657     /**
       
  1658      * Decrypt an EncryptedData element to a byte array.
       
  1659      *
       
  1660      * When passed in an EncryptedData node, returns the decryption
       
  1661      * as a byte array.
       
  1662      *
       
  1663      * Does not modify the source document.
       
  1664      * @param element
       
  1665      * @return the bytes resulting from the decryption
       
  1666      * @throws XMLEncryptionException
       
  1667      */
       
  1668     public byte[] decryptToByteArray(Element element) throws XMLEncryptionException {
       
  1669         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
  1670             log.log(java.util.logging.Level.FINE, "Decrypting to ByteArray...");
       
  1671         }
       
  1672 
       
  1673         if (cipherMode != DECRYPT_MODE) {
       
  1674             log.log(java.util.logging.Level.SEVERE, "XMLCipher unexpectedly not in DECRYPT_MODE...");
       
  1675         }
       
  1676 
       
  1677         EncryptedData encryptedData = factory.newEncryptedData(element);
       
  1678 
       
  1679         if (key == null) {
       
  1680             KeyInfo ki = encryptedData.getKeyInfo();
       
  1681             if (ki != null) {
       
  1682                 try {
       
  1683                     // Add an EncryptedKey resolver
       
  1684                     String encMethodAlgorithm = encryptedData.getEncryptionMethod().getAlgorithm();
       
  1685                     EncryptedKeyResolver resolver = new EncryptedKeyResolver(encMethodAlgorithm, kek);
       
  1686                     if (internalKeyResolvers != null) {
       
  1687                         int size = internalKeyResolvers.size();
       
  1688                         for (int i = 0; i < size; i++) {
       
  1689                             resolver.registerInternalKeyResolver(internalKeyResolvers.get(i));
       
  1690                         }
       
  1691                     }
       
  1692                     ki.registerInternalKeyResolver(resolver);
       
  1693                     ki.setSecureValidation(secureValidation);
       
  1694                     key = ki.getSecretKey();
       
  1695                 } catch (KeyResolverException kre) {
       
  1696                     if (log.isLoggable(java.util.logging.Level.FINE)) {
       
  1697                         log.log(java.util.logging.Level.FINE, kre.getMessage(), kre);
       
  1698                     }
       
  1699                 }
       
  1700             }
       
  1701 
       
  1702             if (key == null) {
       
  1703                 log.log(java.util.logging.Level.SEVERE,
       
  1704                     "XMLCipher::decryptElement called without a key and unable to resolve"
       
  1705                 );
       
  1706                 throw new XMLEncryptionException("encryption.nokey");
       
  1707             }
       
  1708         }
       
  1709 
       
  1710         // Obtain the encrypted octets
       
  1711         XMLCipherInput cipherInput = new XMLCipherInput(encryptedData);
       
  1712         cipherInput.setSecureValidation(secureValidation);
       
  1713         byte[] encryptedBytes = cipherInput.getBytes();
       
  1714 
       
  1715         // Now create the working cipher
       
  1716         String jceAlgorithm =
       
  1717             JCEMapper.translateURItoJCEID(encryptedData.getEncryptionMethod().getAlgorithm());
       
  1718         if (log.isLoggable(java.util.logging.Level.FINE)) {
       
  1719             log.log(java.util.logging.Level.FINE, "JCE Algorithm = " + jceAlgorithm);
       
  1720         }
       
  1721 
       
  1722         Cipher c;
       
  1723         try {
       
  1724             if (requestedJCEProvider == null) {
       
  1725                 c = Cipher.getInstance(jceAlgorithm);
       
  1726             } else {
       
  1727                 c = Cipher.getInstance(jceAlgorithm, requestedJCEProvider);
       
  1728             }
       
  1729         } catch (NoSuchAlgorithmException nsae) {
       
  1730             throw new XMLEncryptionException("empty", nsae);
       
  1731         } catch (NoSuchProviderException nspre) {
       
  1732             throw new XMLEncryptionException("empty", nspre);
       
  1733         } catch (NoSuchPaddingException nspae) {
       
  1734             throw new XMLEncryptionException("empty", nspae);
       
  1735         }
       
  1736 
       
  1737         // Calculate the IV length and copy out
       
  1738 
       
  1739         // For now, we only work with Block ciphers, so this will work.
       
  1740         // This should probably be put into the JCE mapper.
       
  1741 
       
  1742         int ivLen = c.getBlockSize();
       
  1743         String alg = encryptedData.getEncryptionMethod().getAlgorithm();
       
  1744         if (AES_128_GCM.equals(alg) || AES_192_GCM.equals(alg) || AES_256_GCM.equals(alg)) {
       
  1745             ivLen = 12;
       
  1746         }
       
  1747         byte[] ivBytes = new byte[ivLen];
       
  1748 
       
  1749         // You may be able to pass the entire piece in to IvParameterSpec
       
  1750         // and it will only take the first x bytes, but no way to be certain
       
  1751         // that this will work for every JCE provider, so lets copy the
       
  1752         // necessary bytes into a dedicated array.
       
  1753 
       
  1754         System.arraycopy(encryptedBytes, 0, ivBytes, 0, ivLen);
       
  1755         IvParameterSpec iv = new IvParameterSpec(ivBytes);
       
  1756 
       
  1757         try {
       
  1758             c.init(cipherMode, key, iv);
       
  1759         } catch (InvalidKeyException ike) {
       
  1760             throw new XMLEncryptionException("empty", ike);
       
  1761         } catch (InvalidAlgorithmParameterException iape) {
       
  1762             throw new XMLEncryptionException("empty", iape);
       
  1763         }
       
  1764 
       
  1765         try {
       
  1766             return c.doFinal(encryptedBytes, ivLen, encryptedBytes.length - ivLen);
       
  1767         } catch (IllegalBlockSizeException ibse) {
       
  1768             throw new XMLEncryptionException("empty", ibse);
       
  1769         } catch (BadPaddingException bpe) {
       
  1770             throw new XMLEncryptionException("empty", bpe);
       
  1771         }
       
  1772     }
       
  1773 
       
  1774     /*
       
  1775      * Expose the interface for creating XML Encryption objects
       
  1776      */
       
  1777 
       
  1778     /**
       
  1779      * Creates an <code>EncryptedData</code> <code>Element</code>.
       
  1780      *
       
  1781      * The newEncryptedData and newEncryptedKey methods create fairly complete
       
  1782      * elements that are immediately useable.  All the other create* methods
       
  1783      * return bare elements that still need to be built upon.
       
  1784      *<p>
       
  1785      * An EncryptionMethod will still need to be added however
       
  1786      *
       
  1787      * @param type Either REFERENCE_TYPE or VALUE_TYPE - defines what kind of
       
  1788      * CipherData this EncryptedData will contain.
       
  1789      * @param value the Base 64 encoded, encrypted text to wrap in the
       
  1790      *   <code>EncryptedData</code> or the URI to set in the CipherReference
       
  1791      * (usage will depend on the <code>type</code>
       
  1792      * @return the <code>EncryptedData</code> <code>Element</code>.
       
  1793      *
       
  1794      * <!--
       
  1795      * <EncryptedData Id[OPT] Type[OPT] MimeType[OPT] Encoding[OPT]>
       
  1796      *     <EncryptionMethod/>[OPT]
       
  1797      *     <ds:KeyInfo>[OPT]
       
  1798      *         <EncryptedKey/>[OPT]
       
  1799      *         <AgreementMethod/>[OPT]
       
  1800      *         <ds:KeyName/>[OPT]
       
  1801      *         <ds:RetrievalMethod/>[OPT]
       
  1802      *         <ds:[MUL]/>[OPT]
       
  1803      *     </ds:KeyInfo>
       
  1804      *     <CipherData>[MAN]
       
  1805      *         <CipherValue/> XOR <CipherReference/>
       
  1806      *     </CipherData>
       
  1807      *     <EncryptionProperties/>[OPT]
       
  1808      * </EncryptedData>
       
  1809      * -->
       
  1810      * @throws XMLEncryptionException
       
  1811      */
       
  1812     public EncryptedData createEncryptedData(int type, String value) throws XMLEncryptionException {
       
  1813         EncryptedData result = null;
       
  1814         CipherData data = null;
       
  1815 
       
  1816         switch (type) {
       
  1817         case CipherData.REFERENCE_TYPE:
       
  1818             CipherReference cipherReference = factory.newCipherReference(value);
       
  1819             data = factory.newCipherData(type);
       
  1820             data.setCipherReference(cipherReference);
       
  1821             result = factory.newEncryptedData(data);
       
  1822             break;
       
  1823         case CipherData.VALUE_TYPE:
       
  1824             CipherValue cipherValue = factory.newCipherValue(value);
       
  1825             data = factory.newCipherData(type);
       
  1826             data.setCipherValue(cipherValue);
       
  1827             result = factory.newEncryptedData(data);
       
  1828         }
       
  1829 
       
  1830         return result;
       
  1831     }
       
  1832 
       
  1833     /**
       
  1834      * Creates an <code>EncryptedKey</code> <code>Element</code>.
       
  1835      *
       
  1836      * The newEncryptedData and newEncryptedKey methods create fairly complete
       
  1837      * elements that are immediately useable.  All the other create* methods
       
  1838      * return bare elements that still need to be built upon.
       
  1839      *<p>
       
  1840      * An EncryptionMethod will still need to be added however
       
  1841      *
       
  1842      * @param type Either REFERENCE_TYPE or VALUE_TYPE - defines what kind of
       
  1843      * CipherData this EncryptedData will contain.
       
  1844      * @param value the Base 64 encoded, encrypted text to wrap in the
       
  1845      *   <code>EncryptedKey</code> or the URI to set in the CipherReference
       
  1846      * (usage will depend on the <code>type</code>
       
  1847      * @return the <code>EncryptedKey</code> <code>Element</code>.
       
  1848      *
       
  1849      * <!--
       
  1850      * <EncryptedKey Id[OPT] Type[OPT] MimeType[OPT] Encoding[OPT]>
       
  1851      *     <EncryptionMethod/>[OPT]
       
  1852      *     <ds:KeyInfo>[OPT]
       
  1853      *         <EncryptedKey/>[OPT]
       
  1854      *         <AgreementMethod/>[OPT]
       
  1855      *         <ds:KeyName/>[OPT]
       
  1856      *         <ds:RetrievalMethod/>[OPT]
       
  1857      *         <ds:[MUL]/>[OPT]
       
  1858      *     </ds:KeyInfo>
       
  1859      *     <CipherData>[MAN]
       
  1860      *         <CipherValue/> XOR <CipherReference/>
       
  1861      *     </CipherData>
       
  1862      *     <EncryptionProperties/>[OPT]
       
  1863      * </EncryptedData>
       
  1864      * -->
       
  1865      * @throws XMLEncryptionException
       
  1866      */
       
  1867     public EncryptedKey createEncryptedKey(int type, String value) throws XMLEncryptionException {
       
  1868         EncryptedKey result = null;
       
  1869         CipherData data = null;
       
  1870 
       
  1871         switch (type) {
       
  1872         case CipherData.REFERENCE_TYPE:
       
  1873             CipherReference cipherReference = factory.newCipherReference(value);
       
  1874             data = factory.newCipherData(type);
       
  1875             data.setCipherReference(cipherReference);
       
  1876             result = factory.newEncryptedKey(data);
       
  1877             break;
       
  1878         case CipherData.VALUE_TYPE:
       
  1879             CipherValue cipherValue = factory.newCipherValue(value);
       
  1880             data = factory.newCipherData(type);
       
  1881             data.setCipherValue(cipherValue);
       
  1882             result = factory.newEncryptedKey(data);
       
  1883         }
       
  1884 
       
  1885         return result;
       
  1886     }
       
  1887 
       
  1888     /**
       
  1889      * Create an AgreementMethod object
       
  1890      *
       
  1891      * @param algorithm Algorithm of the agreement method
       
  1892      * @return a new <code>AgreementMethod</code>
       
  1893      */
       
  1894     public AgreementMethod createAgreementMethod(String algorithm) {
       
  1895         return factory.newAgreementMethod(algorithm);
       
  1896     }
       
  1897 
       
  1898     /**
       
  1899      * Create a CipherData object
       
  1900      *
       
  1901      * @param type Type of this CipherData (either VALUE_TUPE or
       
  1902      * REFERENCE_TYPE)
       
  1903      * @return a new <code>CipherData</code>
       
  1904      */
       
  1905     public CipherData createCipherData(int type) {
       
  1906         return factory.newCipherData(type);
       
  1907     }
       
  1908 
       
  1909     /**
       
  1910      * Create a CipherReference object
       
  1911      *
       
  1912      * @param uri The URI that the reference will refer
       
  1913      * @return a new <code>CipherReference</code>
       
  1914      */
       
  1915     public CipherReference createCipherReference(String uri) {
       
  1916         return factory.newCipherReference(uri);
       
  1917     }
       
  1918 
       
  1919     /**
       
  1920      * Create a CipherValue element
       
  1921      *
       
  1922      * @param value The value to set the ciphertext to
       
  1923      * @return a new <code>CipherValue</code>
       
  1924      */
       
  1925     public CipherValue createCipherValue(String value) {
       
  1926         return factory.newCipherValue(value);
       
  1927     }
       
  1928 
       
  1929     /**
       
  1930      * Create an EncryptionMethod object
       
  1931      *
       
  1932      * @param algorithm Algorithm for the encryption
       
  1933      * @return a new <code>EncryptionMethod</code>
       
  1934      */
       
  1935     public EncryptionMethod createEncryptionMethod(String algorithm) {
       
  1936         return factory.newEncryptionMethod(algorithm);
       
  1937     }
       
  1938 
       
  1939     /**
       
  1940      * Create an EncryptionProperties element
       
  1941      * @return a new <code>EncryptionProperties</code>
       
  1942      */
       
  1943     public EncryptionProperties createEncryptionProperties() {
       
  1944         return factory.newEncryptionProperties();
       
  1945     }
       
  1946 
       
  1947     /**
       
  1948      * Create a new EncryptionProperty element
       
  1949      * @return a new <code>EncryptionProperty</code>
       
  1950      */
       
  1951     public EncryptionProperty createEncryptionProperty() {
       
  1952         return factory.newEncryptionProperty();
       
  1953     }
       
  1954 
       
  1955     /**
       
  1956      * Create a new ReferenceList object
       
  1957      * @param type ReferenceList.DATA_REFERENCE or ReferenceList.KEY_REFERENCE
       
  1958      * @return a new <code>ReferenceList</code>
       
  1959      */
       
  1960     public ReferenceList createReferenceList(int type) {
       
  1961         return factory.newReferenceList(type);
       
  1962     }
       
  1963 
       
  1964     /**
       
  1965      * Create a new Transforms object
       
  1966      * <p>
       
  1967      * <b>Note</b>: A context document <i>must</i> have been set
       
  1968      * elsewhere (possibly via a call to doFinal).  If not, use the
       
  1969      * createTransforms(Document) method.
       
  1970      * @return a new <code>Transforms</code>
       
  1971      */
       
  1972     public Transforms createTransforms() {
       
  1973         return factory.newTransforms();
       
  1974     }
       
  1975 
       
  1976     /**
       
  1977      * Create a new Transforms object
       
  1978      *
       
  1979      * Because the handling of Transforms is currently done in the signature
       
  1980      * code, the creation of a Transforms object <b>requires</b> a
       
  1981      * context document.
       
  1982      *
       
  1983      * @param doc Document that will own the created Transforms node
       
  1984      * @return a new <code>Transforms</code>
       
  1985      */
       
  1986     public Transforms createTransforms(Document doc) {
       
  1987         return factory.newTransforms(doc);
       
  1988     }
       
  1989 
       
  1990     /**
       
  1991      *
       
  1992      * @author Axl Mattheus
       
  1993      */
       
  1994     private class Factory {
       
  1995         /**
       
  1996          * @param algorithm
       
  1997          * @return a new AgreementMethod
       
  1998          */
       
  1999         AgreementMethod newAgreementMethod(String algorithm)  {
       
  2000             return new AgreementMethodImpl(algorithm);
       
  2001         }
       
  2002 
       
  2003         /**
       
  2004          * @param type
       
  2005          * @return a new CipherData
       
  2006          *
       
  2007          */
       
  2008         CipherData newCipherData(int type) {
       
  2009             return new CipherDataImpl(type);
       
  2010         }
       
  2011 
       
  2012         /**
       
  2013          * @param uri
       
  2014          * @return a new CipherReference
       
  2015          */
       
  2016         CipherReference newCipherReference(String uri)  {
       
  2017             return new CipherReferenceImpl(uri);
       
  2018         }
       
  2019 
       
  2020         /**
       
  2021          * @param value
       
  2022          * @return a new CipherValue
       
  2023          */
       
  2024         CipherValue newCipherValue(String value) {
       
  2025             return new CipherValueImpl(value);
       
  2026         }
       
  2027 
       
  2028         /*
       
  2029         CipherValue newCipherValue(byte[] value) {
       
  2030             return new CipherValueImpl(value);
       
  2031         }
       
  2032          */
       
  2033 
       
  2034         /**
       
  2035          * @param data
       
  2036          * @return a new EncryptedData
       
  2037          */
       
  2038         EncryptedData newEncryptedData(CipherData data) {
       
  2039             return new EncryptedDataImpl(data);
       
  2040         }
       
  2041 
       
  2042         /**
       
  2043          * @param data
       
  2044          * @return a new EncryptedKey
       
  2045          */
       
  2046         EncryptedKey newEncryptedKey(CipherData data) {
       
  2047             return new EncryptedKeyImpl(data);
       
  2048         }
       
  2049 
       
  2050         /**
       
  2051          * @param algorithm
       
  2052          * @return a new EncryptionMethod
       
  2053          */
       
  2054         EncryptionMethod newEncryptionMethod(String algorithm) {
       
  2055             return new EncryptionMethodImpl(algorithm);
       
  2056         }
       
  2057 
       
  2058         /**
       
  2059          * @return a new EncryptionProperties
       
  2060          */
       
  2061         EncryptionProperties newEncryptionProperties() {
       
  2062             return new EncryptionPropertiesImpl();
       
  2063         }
       
  2064 
       
  2065         /**
       
  2066          * @return a new EncryptionProperty
       
  2067          */
       
  2068         EncryptionProperty newEncryptionProperty() {
       
  2069             return new EncryptionPropertyImpl();
       
  2070         }
       
  2071 
       
  2072         /**
       
  2073          * @param type ReferenceList.DATA_REFERENCE or ReferenceList.KEY_REFERENCE
       
  2074          * @return a new ReferenceList
       
  2075          */
       
  2076         ReferenceList newReferenceList(int type) {
       
  2077             return new ReferenceListImpl(type);
       
  2078         }
       
  2079 
       
  2080         /**
       
  2081          * @return a new Transforms
       
  2082          */
       
  2083         Transforms newTransforms() {
       
  2084             return new TransformsImpl();
       
  2085         }
       
  2086 
       
  2087         /**
       
  2088          * @param doc
       
  2089          * @return a new Transforms
       
  2090          */
       
  2091         Transforms newTransforms(Document doc) {
       
  2092             return new TransformsImpl(doc);
       
  2093         }
       
  2094 
       
  2095         /**
       
  2096          * @param element
       
  2097          * @return a new CipherData
       
  2098          * @throws XMLEncryptionException
       
  2099          */
       
  2100         CipherData newCipherData(Element element) throws XMLEncryptionException {
       
  2101             if (null == element) {
       
  2102                 throw new NullPointerException("element is null");
       
  2103             }
       
  2104 
       
  2105             int type = 0;
       
  2106             Element e = null;
       
  2107             if (element.getElementsByTagNameNS(
       
  2108                 EncryptionConstants.EncryptionSpecNS,
       
  2109                 EncryptionConstants._TAG_CIPHERVALUE).getLength() > 0
       
  2110             ) {
       
  2111                 type = CipherData.VALUE_TYPE;
       
  2112                 e = (Element) element.getElementsByTagNameNS(
       
  2113                     EncryptionConstants.EncryptionSpecNS,
       
  2114                     EncryptionConstants._TAG_CIPHERVALUE).item(0);
       
  2115             } else if (element.getElementsByTagNameNS(
       
  2116                 EncryptionConstants.EncryptionSpecNS,
       
  2117                 EncryptionConstants._TAG_CIPHERREFERENCE).getLength() > 0) {
       
  2118                 type = CipherData.REFERENCE_TYPE;
       
  2119                 e = (Element) element.getElementsByTagNameNS(
       
  2120                     EncryptionConstants.EncryptionSpecNS,
       
  2121                     EncryptionConstants._TAG_CIPHERREFERENCE).item(0);
       
  2122             }
       
  2123 
       
  2124             CipherData result = newCipherData(type);
       
  2125             if (type == CipherData.VALUE_TYPE) {
       
  2126                 result.setCipherValue(newCipherValue(e));
       
  2127             } else if (type == CipherData.REFERENCE_TYPE) {
       
  2128                 result.setCipherReference(newCipherReference(e));
       
  2129             }
       
  2130 
       
  2131             return result;
       
  2132         }
       
  2133 
       
  2134         /**
       
  2135          * @param element
       
  2136          * @return a new CipherReference
       
  2137          * @throws XMLEncryptionException
       
  2138          *
       
  2139          */
       
  2140         CipherReference newCipherReference(Element element) throws XMLEncryptionException {
       
  2141 
       
  2142             Attr uriAttr =
       
  2143                 element.getAttributeNodeNS(null, EncryptionConstants._ATT_URI);
       
  2144             CipherReference result = new CipherReferenceImpl(uriAttr);
       
  2145 
       
  2146             // Find any Transforms
       
  2147             NodeList transformsElements =
       
  2148                 element.getElementsByTagNameNS(
       
  2149                     EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_TRANSFORMS);
       
  2150             Element transformsElement = (Element) transformsElements.item(0);
       
  2151 
       
  2152             if (transformsElement != null) {
       
  2153                 if (log.isLoggable(java.util.logging.Level.FINE)) {
       
  2154                     log.log(java.util.logging.Level.FINE, "Creating a DSIG based Transforms element");
       
  2155                 }
       
  2156                 try {
       
  2157                     result.setTransforms(new TransformsImpl(transformsElement));
       
  2158                 } catch (XMLSignatureException xse) {
       
  2159                     throw new XMLEncryptionException("empty", xse);
       
  2160                 } catch (InvalidTransformException ite) {
       
  2161                     throw new XMLEncryptionException("empty", ite);
       
  2162                 } catch (XMLSecurityException xse) {
       
  2163                     throw new XMLEncryptionException("empty", xse);
       
  2164                 }
       
  2165             }
       
  2166 
       
  2167             return result;
       
  2168         }
       
  2169 
       
  2170         /**
       
  2171          * @param element
       
  2172          * @return a new CipherValue
       
  2173          */
       
  2174         CipherValue newCipherValue(Element element) {
       
  2175             String value = XMLUtils.getFullTextChildrenFromElement(element);
       
  2176 
       
  2177             return newCipherValue(value);
       
  2178         }
       
  2179 
       
  2180         /**
       
  2181          * @param element
       
  2182          * @return a new EncryptedData
       
  2183          * @throws XMLEncryptionException
       
  2184          *
       
  2185          */
       
  2186         EncryptedData newEncryptedData(Element element) throws XMLEncryptionException {
       
  2187             EncryptedData result = null;
       
  2188 
       
  2189             NodeList dataElements =
       
  2190                 element.getElementsByTagNameNS(
       
  2191                     EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_CIPHERDATA);
       
  2192 
       
  2193             // Need to get the last CipherData found, as earlier ones will
       
  2194             // be for elements in the KeyInfo lists
       
  2195 
       
  2196             Element dataElement =
       
  2197                 (Element) dataElements.item(dataElements.getLength() - 1);
       
  2198 
       
  2199             CipherData data = newCipherData(dataElement);
       
  2200 
       
  2201             result = newEncryptedData(data);
       
  2202 
       
  2203             result.setId(element.getAttributeNS(null, EncryptionConstants._ATT_ID));
       
  2204             result.setType(element.getAttributeNS(null, EncryptionConstants._ATT_TYPE));
       
  2205             result.setMimeType(element.getAttributeNS(null, EncryptionConstants._ATT_MIMETYPE));
       
  2206             result.setEncoding( element.getAttributeNS(null, Constants._ATT_ENCODING));
       
  2207 
       
  2208             Element encryptionMethodElement =
       
  2209                 (Element) element.getElementsByTagNameNS(
       
  2210                     EncryptionConstants.EncryptionSpecNS,
       
  2211                     EncryptionConstants._TAG_ENCRYPTIONMETHOD).item(0);
       
  2212             if (null != encryptionMethodElement) {
       
  2213                 result.setEncryptionMethod(newEncryptionMethod(encryptionMethodElement));
       
  2214             }
       
  2215 
       
  2216             // BFL 16/7/03 - simple implementation
       
  2217             // TODO: Work out how to handle relative URI
       
  2218 
       
  2219             Element keyInfoElement =
       
  2220                 (Element) element.getElementsByTagNameNS(
       
  2221                     Constants.SignatureSpecNS, Constants._TAG_KEYINFO).item(0);
       
  2222             if (null != keyInfoElement) {
       
  2223                 KeyInfo ki = newKeyInfo(keyInfoElement);
       
  2224                 result.setKeyInfo(ki);
       
  2225             }
       
  2226 
       
  2227             // TODO: Implement
       
  2228             Element encryptionPropertiesElement =
       
  2229                 (Element) element.getElementsByTagNameNS(
       
  2230                     EncryptionConstants.EncryptionSpecNS,
       
  2231                     EncryptionConstants._TAG_ENCRYPTIONPROPERTIES).item(0);
       
  2232             if (null != encryptionPropertiesElement) {
       
  2233                 result.setEncryptionProperties(
       
  2234                     newEncryptionProperties(encryptionPropertiesElement)
       
  2235                 );
       
  2236             }
       
  2237 
       
  2238             return result;
       
  2239         }
       
  2240 
       
  2241         /**
       
  2242          * @param element
       
  2243          * @return a new EncryptedKey
       
  2244          * @throws XMLEncryptionException
       
  2245          */
       
  2246         EncryptedKey newEncryptedKey(Element element) throws XMLEncryptionException {
       
  2247             EncryptedKey result = null;
       
  2248             NodeList dataElements =
       
  2249                 element.getElementsByTagNameNS(
       
  2250                     EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_CIPHERDATA);
       
  2251             Element dataElement =
       
  2252                 (Element) dataElements.item(dataElements.getLength() - 1);
       
  2253 
       
  2254             CipherData data = newCipherData(dataElement);
       
  2255             result = newEncryptedKey(data);
       
  2256 
       
  2257             result.setId(element.getAttributeNS(null, EncryptionConstants._ATT_ID));
       
  2258             result.setType(element.getAttributeNS(null, EncryptionConstants._ATT_TYPE));
       
  2259             result.setMimeType(element.getAttributeNS(null, EncryptionConstants._ATT_MIMETYPE));
       
  2260             result.setEncoding(element.getAttributeNS(null, Constants._ATT_ENCODING));
       
  2261             result.setRecipient(element.getAttributeNS(null, EncryptionConstants._ATT_RECIPIENT));
       
  2262 
       
  2263             Element encryptionMethodElement =
       
  2264                 (Element) element.getElementsByTagNameNS(
       
  2265                     EncryptionConstants.EncryptionSpecNS,
       
  2266                     EncryptionConstants._TAG_ENCRYPTIONMETHOD).item(0);
       
  2267             if (null != encryptionMethodElement) {
       
  2268                 result.setEncryptionMethod(newEncryptionMethod(encryptionMethodElement));
       
  2269             }
       
  2270 
       
  2271             Element keyInfoElement =
       
  2272                 (Element) element.getElementsByTagNameNS(
       
  2273                     Constants.SignatureSpecNS, Constants._TAG_KEYINFO).item(0);
       
  2274             if (null != keyInfoElement) {
       
  2275                 KeyInfo ki = newKeyInfo(keyInfoElement);
       
  2276                 result.setKeyInfo(ki);
       
  2277             }
       
  2278 
       
  2279             // TODO: Implement
       
  2280             Element encryptionPropertiesElement =
       
  2281                 (Element) element.getElementsByTagNameNS(
       
  2282                     EncryptionConstants.EncryptionSpecNS,
       
  2283                     EncryptionConstants._TAG_ENCRYPTIONPROPERTIES).item(0);
       
  2284             if (null != encryptionPropertiesElement) {
       
  2285                 result.setEncryptionProperties(
       
  2286                     newEncryptionProperties(encryptionPropertiesElement)
       
  2287                 );
       
  2288             }
       
  2289 
       
  2290             Element referenceListElement =
       
  2291                 (Element) element.getElementsByTagNameNS(
       
  2292                     EncryptionConstants.EncryptionSpecNS,
       
  2293                     EncryptionConstants._TAG_REFERENCELIST).item(0);
       
  2294             if (null != referenceListElement) {
       
  2295                 result.setReferenceList(newReferenceList(referenceListElement));
       
  2296             }
       
  2297 
       
  2298             Element carriedNameElement =
       
  2299                 (Element) element.getElementsByTagNameNS(
       
  2300                     EncryptionConstants.EncryptionSpecNS,
       
  2301                     EncryptionConstants._TAG_CARRIEDKEYNAME).item(0);
       
  2302             if (null != carriedNameElement) {
       
  2303                 result.setCarriedName(carriedNameElement.getFirstChild().getNodeValue());
       
  2304             }
       
  2305 
       
  2306             return result;
       
  2307         }
       
  2308 
       
  2309         /**
       
  2310          * @param element
       
  2311          * @return a new KeyInfo
       
  2312          * @throws XMLEncryptionException
       
  2313          */
       
  2314         KeyInfo newKeyInfo(Element element) throws XMLEncryptionException {
       
  2315             try {
       
  2316                 KeyInfo ki = new KeyInfo(element, null);
       
  2317                 ki.setSecureValidation(secureValidation);
       
  2318                 if (internalKeyResolvers != null) {
       
  2319                     int size = internalKeyResolvers.size();
       
  2320                     for (int i = 0; i < size; i++) {
       
  2321                         ki.registerInternalKeyResolver(internalKeyResolvers.get(i));
       
  2322                     }
       
  2323                 }
       
  2324                 return ki;
       
  2325             } catch (XMLSecurityException xse) {
       
  2326                 throw new XMLEncryptionException("Error loading Key Info", xse);
       
  2327             }
       
  2328         }
       
  2329 
       
  2330         /**
       
  2331          * @param element
       
  2332          * @return a new EncryptionMethod
       
  2333          */
       
  2334         EncryptionMethod newEncryptionMethod(Element element) {
       
  2335             String encAlgorithm = element.getAttributeNS(null, EncryptionConstants._ATT_ALGORITHM);
       
  2336             EncryptionMethod result = newEncryptionMethod(encAlgorithm);
       
  2337 
       
  2338             Element keySizeElement =
       
  2339                 (Element) element.getElementsByTagNameNS(
       
  2340                     EncryptionConstants.EncryptionSpecNS,
       
  2341                     EncryptionConstants._TAG_KEYSIZE).item(0);
       
  2342             if (null != keySizeElement) {
       
  2343                 result.setKeySize(
       
  2344                     Integer.valueOf(
       
  2345                         keySizeElement.getFirstChild().getNodeValue()).intValue());
       
  2346             }
       
  2347 
       
  2348             Element oaepParamsElement =
       
  2349                 (Element) element.getElementsByTagNameNS(
       
  2350                     EncryptionConstants.EncryptionSpecNS,
       
  2351                     EncryptionConstants._TAG_OAEPPARAMS).item(0);
       
  2352             if (null != oaepParamsElement) {
       
  2353                 try {
       
  2354                     String oaepParams = oaepParamsElement.getFirstChild().getNodeValue();
       
  2355                     result.setOAEPparams(Base64.decode(oaepParams.getBytes("UTF-8")));
       
  2356                 } catch(UnsupportedEncodingException e) {
       
  2357                     throw new RuntimeException("UTF-8 not supported", e);
       
  2358                 } catch (Base64DecodingException e) {
       
  2359                     throw new RuntimeException("BASE-64 decoding error", e);
       
  2360                 }
       
  2361             }
       
  2362 
       
  2363             Element digestElement =
       
  2364                 (Element) element.getElementsByTagNameNS(
       
  2365                     Constants.SignatureSpecNS, Constants._TAG_DIGESTMETHOD).item(0);
       
  2366             if (digestElement != null) {
       
  2367                 String digestAlgorithm = digestElement.getAttributeNS(null, "Algorithm");
       
  2368                 result.setDigestAlgorithm(digestAlgorithm);
       
  2369             }
       
  2370 
       
  2371             Element mgfElement =
       
  2372                 (Element) element.getElementsByTagNameNS(
       
  2373                     EncryptionConstants.EncryptionSpec11NS, EncryptionConstants._TAG_MGF).item(0);
       
  2374             if (mgfElement != null && !XMLCipher.RSA_OAEP.equals(algorithm)) {
       
  2375                 String mgfAlgorithm = mgfElement.getAttributeNS(null, "Algorithm");
       
  2376                 result.setMGFAlgorithm(mgfAlgorithm);
       
  2377             }
       
  2378 
       
  2379             // TODO: Make this mess work
       
  2380             // <any namespace='##other' minOccurs='0' maxOccurs='unbounded'/>
       
  2381 
       
  2382             return result;
       
  2383         }
       
  2384 
       
  2385         /**
       
  2386          * @param element
       
  2387          * @return a new EncryptionProperties
       
  2388          */
       
  2389         EncryptionProperties newEncryptionProperties(Element element) {
       
  2390             EncryptionProperties result = newEncryptionProperties();
       
  2391 
       
  2392             result.setId(element.getAttributeNS(null, EncryptionConstants._ATT_ID));
       
  2393 
       
  2394             NodeList encryptionPropertyList =
       
  2395                 element.getElementsByTagNameNS(
       
  2396                     EncryptionConstants.EncryptionSpecNS,
       
  2397                     EncryptionConstants._TAG_ENCRYPTIONPROPERTY);
       
  2398             for (int i = 0; i < encryptionPropertyList.getLength(); i++) {
       
  2399                 Node n = encryptionPropertyList.item(i);
       
  2400                 if (null != n) {
       
  2401                     result.addEncryptionProperty(newEncryptionProperty((Element) n));
       
  2402                 }
       
  2403             }
       
  2404 
       
  2405             return result;
       
  2406         }
       
  2407 
       
  2408         /**
       
  2409          * @param element
       
  2410          * @return a new EncryptionProperty
       
  2411          */
       
  2412         EncryptionProperty newEncryptionProperty(Element element) {
       
  2413             EncryptionProperty result = newEncryptionProperty();
       
  2414 
       
  2415             result.setTarget(element.getAttributeNS(null, EncryptionConstants._ATT_TARGET));
       
  2416             result.setId(element.getAttributeNS(null, EncryptionConstants._ATT_ID));
       
  2417             // TODO: Make this lot work...
       
  2418             // <anyAttribute namespace="http://www.w3.org/XML/1998/namespace"/>
       
  2419 
       
  2420             // TODO: Make this work...
       
  2421             // <any namespace='##other' processContents='lax'/>
       
  2422 
       
  2423             return result;
       
  2424         }
       
  2425 
       
  2426         /**
       
  2427          * @param element
       
  2428          * @return a new ReferenceList
       
  2429          */
       
  2430         ReferenceList newReferenceList(Element element) {
       
  2431             int type = 0;
       
  2432             if (null != element.getElementsByTagNameNS(
       
  2433                 EncryptionConstants.EncryptionSpecNS,
       
  2434                 EncryptionConstants._TAG_DATAREFERENCE).item(0)) {
       
  2435                 type = ReferenceList.DATA_REFERENCE;
       
  2436             } else if (null != element.getElementsByTagNameNS(
       
  2437                 EncryptionConstants.EncryptionSpecNS,
       
  2438                 EncryptionConstants._TAG_KEYREFERENCE).item(0)) {
       
  2439                 type = ReferenceList.KEY_REFERENCE;
       
  2440             }
       
  2441 
       
  2442             ReferenceList result = new ReferenceListImpl(type);
       
  2443             NodeList list = null;
       
  2444             switch (type) {
       
  2445             case ReferenceList.DATA_REFERENCE:
       
  2446                 list =
       
  2447                     element.getElementsByTagNameNS(
       
  2448                         EncryptionConstants.EncryptionSpecNS,
       
  2449                         EncryptionConstants._TAG_DATAREFERENCE);
       
  2450                 for (int i = 0; i < list.getLength() ; i++) {
       
  2451                     String uri = ((Element) list.item(i)).getAttribute("URI");
       
  2452                     result.add(result.newDataReference(uri));
       
  2453                 }
       
  2454                 break;
       
  2455             case ReferenceList.KEY_REFERENCE:
       
  2456                 list =
       
  2457                     element.getElementsByTagNameNS(
       
  2458                         EncryptionConstants.EncryptionSpecNS,
       
  2459                         EncryptionConstants._TAG_KEYREFERENCE);
       
  2460                 for (int i = 0; i < list.getLength() ; i++) {
       
  2461                     String uri = ((Element) list.item(i)).getAttribute("URI");
       
  2462                     result.add(result.newKeyReference(uri));
       
  2463                 }
       
  2464             }
       
  2465 
       
  2466             return result;
       
  2467         }
       
  2468 
       
  2469         /**
       
  2470          * @param encryptedData
       
  2471          * @return the XML Element form of that EncryptedData
       
  2472          */
       
  2473         Element toElement(EncryptedData encryptedData) {
       
  2474             return ((EncryptedDataImpl) encryptedData).toElement();
       
  2475         }
       
  2476 
       
  2477         /**
       
  2478          * @param encryptedKey
       
  2479          * @return the XML Element form of that EncryptedKey
       
  2480          */
       
  2481         Element toElement(EncryptedKey encryptedKey) {
       
  2482             return ((EncryptedKeyImpl) encryptedKey).toElement();
       
  2483         }
       
  2484 
       
  2485         /**
       
  2486          * @param referenceList
       
  2487          * @return the XML Element form of that ReferenceList
       
  2488          */
       
  2489         Element toElement(ReferenceList referenceList) {
       
  2490             return ((ReferenceListImpl) referenceList).toElement();
       
  2491         }
       
  2492 
       
  2493         private class AgreementMethodImpl implements AgreementMethod {
       
  2494             private byte[] kaNonce = null;
       
  2495             private List<Element> agreementMethodInformation = null;
       
  2496             private KeyInfo originatorKeyInfo = null;
       
  2497             private KeyInfo recipientKeyInfo = null;
       
  2498             private String algorithmURI = null;
       
  2499 
       
  2500             /**
       
  2501              * @param algorithm
       
  2502              */
       
  2503             public AgreementMethodImpl(String algorithm) {
       
  2504                 agreementMethodInformation = new LinkedList<Element>();
       
  2505                 URI tmpAlgorithm = null;
       
  2506                 try {
       
  2507                     tmpAlgorithm = new URI(algorithm);
       
  2508                 } catch (URISyntaxException ex) {
       
  2509                     throw (IllegalArgumentException)
       
  2510                     new IllegalArgumentException().initCause(ex);
       
  2511                 }
       
  2512                 algorithmURI = tmpAlgorithm.toString();
       
  2513             }
       
  2514 
       
  2515             /** @inheritDoc */
       
  2516             public byte[] getKANonce() {
       
  2517                 return kaNonce;
       
  2518             }
       
  2519 
       
  2520             /** @inheritDoc */
       
  2521             public void setKANonce(byte[] kanonce) {
       
  2522                 kaNonce = kanonce;
       
  2523             }
       
  2524 
       
  2525             /** @inheritDoc */
       
  2526             public Iterator<Element> getAgreementMethodInformation() {
       
  2527                 return agreementMethodInformation.iterator();
       
  2528             }
       
  2529 
       
  2530             /** @inheritDoc */
       
  2531             public void addAgreementMethodInformation(Element info) {
       
  2532                 agreementMethodInformation.add(info);
       
  2533             }
       
  2534 
       
  2535             /** @inheritDoc */
       
  2536             public void revoveAgreementMethodInformation(Element info) {
       
  2537                 agreementMethodInformation.remove(info);
       
  2538             }
       
  2539 
       
  2540             /** @inheritDoc */
       
  2541             public KeyInfo getOriginatorKeyInfo() {
       
  2542                 return originatorKeyInfo;
       
  2543             }
       
  2544 
       
  2545             /** @inheritDoc */
       
  2546             public void setOriginatorKeyInfo(KeyInfo keyInfo) {
       
  2547                 originatorKeyInfo = keyInfo;
       
  2548             }
       
  2549 
       
  2550             /** @inheritDoc */
       
  2551             public KeyInfo getRecipientKeyInfo() {
       
  2552                 return recipientKeyInfo;
       
  2553             }
       
  2554 
       
  2555             /** @inheritDoc */
       
  2556             public void setRecipientKeyInfo(KeyInfo keyInfo) {
       
  2557                 recipientKeyInfo = keyInfo;
       
  2558             }
       
  2559 
       
  2560             /** @inheritDoc */
       
  2561             public String getAlgorithm() {
       
  2562                 return algorithmURI;
       
  2563             }
       
  2564         }
       
  2565 
       
  2566         private class CipherDataImpl implements CipherData {
       
  2567             private static final String valueMessage =
       
  2568                 "Data type is reference type.";
       
  2569             private static final String referenceMessage =
       
  2570                 "Data type is value type.";
       
  2571             private CipherValue cipherValue = null;
       
  2572             private CipherReference cipherReference = null;
       
  2573             private int cipherType = Integer.MIN_VALUE;
       
  2574 
       
  2575             /**
       
  2576              * @param type
       
  2577              */
       
  2578             public CipherDataImpl(int type) {
       
  2579                 cipherType = type;
       
  2580             }
       
  2581 
       
  2582             /** @inheritDoc */
       
  2583             public CipherValue getCipherValue() {
       
  2584                 return cipherValue;
       
  2585             }
       
  2586 
       
  2587             /** @inheritDoc */
       
  2588             public void setCipherValue(CipherValue value) throws XMLEncryptionException {
       
  2589 
       
  2590                 if (cipherType == REFERENCE_TYPE) {
       
  2591                     throw new XMLEncryptionException(
       
  2592                         "empty", new UnsupportedOperationException(valueMessage)
       
  2593                     );
       
  2594                 }
       
  2595 
       
  2596                 cipherValue = value;
       
  2597             }
       
  2598 
       
  2599             /** @inheritDoc */
       
  2600             public CipherReference getCipherReference() {
       
  2601                 return cipherReference;
       
  2602             }
       
  2603 
       
  2604             /** @inheritDoc */
       
  2605             public void setCipherReference(CipherReference reference) throws
       
  2606             XMLEncryptionException {
       
  2607                 if (cipherType == VALUE_TYPE) {
       
  2608                     throw new XMLEncryptionException(
       
  2609                         "empty", new UnsupportedOperationException(referenceMessage)
       
  2610                     );
       
  2611                 }
       
  2612 
       
  2613                 cipherReference = reference;
       
  2614             }
       
  2615 
       
  2616             /** @inheritDoc */
       
  2617             public int getDataType() {
       
  2618                 return cipherType;
       
  2619             }
       
  2620 
       
  2621             Element toElement() {
       
  2622                 Element result =
       
  2623                     XMLUtils.createElementInEncryptionSpace(
       
  2624                         contextDocument, EncryptionConstants._TAG_CIPHERDATA
       
  2625                     );
       
  2626                 if (cipherType == VALUE_TYPE) {
       
  2627                     result.appendChild(((CipherValueImpl) cipherValue).toElement());
       
  2628                 } else if (cipherType == REFERENCE_TYPE) {
       
  2629                     result.appendChild(((CipherReferenceImpl) cipherReference).toElement());
       
  2630                 }
       
  2631 
       
  2632                 return result;
       
  2633             }
       
  2634         }
       
  2635 
       
  2636         private class CipherReferenceImpl implements CipherReference {
       
  2637             private String referenceURI = null;
       
  2638             private Transforms referenceTransforms = null;
       
  2639             private Attr referenceNode = null;
       
  2640 
       
  2641             /**
       
  2642              * @param uri
       
  2643              */
       
  2644             public CipherReferenceImpl(String uri) {
       
  2645                 /* Don't check validity of URI as may be "" */
       
  2646                 referenceURI = uri;
       
  2647                 referenceNode = null;
       
  2648             }
       
  2649 
       
  2650             /**
       
  2651              * @param uri
       
  2652              */
       
  2653             public CipherReferenceImpl(Attr uri) {
       
  2654                 referenceURI = uri.getNodeValue();
       
  2655                 referenceNode = uri;
       
  2656             }
       
  2657 
       
  2658             /** @inheritDoc */
       
  2659             public String getURI() {
       
  2660                 return referenceURI;
       
  2661             }
       
  2662 
       
  2663             /** @inheritDoc */
       
  2664             public Attr getURIAsAttr() {
       
  2665                 return referenceNode;
       
  2666             }
       
  2667 
       
  2668             /** @inheritDoc */
       
  2669             public Transforms getTransforms() {
       
  2670                 return referenceTransforms;
       
  2671             }
       
  2672 
       
  2673             /** @inheritDoc */
       
  2674             public void setTransforms(Transforms transforms) {
       
  2675                 referenceTransforms = transforms;
       
  2676             }
       
  2677 
       
  2678             Element toElement() {
       
  2679                 Element result =
       
  2680                     XMLUtils.createElementInEncryptionSpace(
       
  2681                         contextDocument, EncryptionConstants._TAG_CIPHERREFERENCE
       
  2682                     );
       
  2683                 result.setAttributeNS(null, EncryptionConstants._ATT_URI, referenceURI);
       
  2684                 if (null != referenceTransforms) {
       
  2685                     result.appendChild(((TransformsImpl) referenceTransforms).toElement());
       
  2686                 }
       
  2687 
       
  2688                 return result;
       
  2689             }
       
  2690         }
       
  2691 
       
  2692         private class CipherValueImpl implements CipherValue {
       
  2693             private String cipherValue = null;
       
  2694 
       
  2695             /**
       
  2696              * @param value
       
  2697              */
       
  2698             public CipherValueImpl(String value) {
       
  2699                 cipherValue = value;
       
  2700             }
       
  2701 
       
  2702             /** @inheritDoc */
       
  2703             public String getValue() {
       
  2704                 return cipherValue;
       
  2705             }
       
  2706 
       
  2707             /** @inheritDoc */
       
  2708             public void setValue(String value) {
       
  2709                 cipherValue = value;
       
  2710             }
       
  2711 
       
  2712             Element toElement() {
       
  2713                 Element result =
       
  2714                     XMLUtils.createElementInEncryptionSpace(
       
  2715                         contextDocument, EncryptionConstants._TAG_CIPHERVALUE
       
  2716                     );
       
  2717                 result.appendChild(contextDocument.createTextNode(cipherValue));
       
  2718 
       
  2719                 return result;
       
  2720             }
       
  2721         }
       
  2722 
       
  2723         private class EncryptedDataImpl extends EncryptedTypeImpl implements EncryptedData {
       
  2724 
       
  2725             /**
       
  2726              * @param data
       
  2727              */
       
  2728             public EncryptedDataImpl(CipherData data) {
       
  2729                 super(data);
       
  2730             }
       
  2731 
       
  2732             Element toElement() {
       
  2733                 Element result =
       
  2734                     ElementProxy.createElementForFamily(
       
  2735                         contextDocument, EncryptionConstants.EncryptionSpecNS,
       
  2736                         EncryptionConstants._TAG_ENCRYPTEDDATA
       
  2737                     );
       
  2738 
       
  2739                 if (null != super.getId()) {
       
  2740                     result.setAttributeNS(null, EncryptionConstants._ATT_ID, super.getId());
       
  2741                 }
       
  2742                 if (null != super.getType()) {
       
  2743                     result.setAttributeNS(null, EncryptionConstants._ATT_TYPE, super.getType());
       
  2744                 }
       
  2745                 if (null != super.getMimeType()) {
       
  2746                     result.setAttributeNS(
       
  2747                         null, EncryptionConstants._ATT_MIMETYPE, super.getMimeType()
       
  2748                     );
       
  2749                 }
       
  2750                 if (null != super.getEncoding()) {
       
  2751                     result.setAttributeNS(
       
  2752                         null, EncryptionConstants._ATT_ENCODING, super.getEncoding()
       
  2753                     );
       
  2754                 }
       
  2755                 if (null != super.getEncryptionMethod()) {
       
  2756                     result.appendChild(
       
  2757                         ((EncryptionMethodImpl)super.getEncryptionMethod()).toElement()
       
  2758                     );
       
  2759                 }
       
  2760                 if (null != super.getKeyInfo()) {
       
  2761                     result.appendChild(super.getKeyInfo().getElement().cloneNode(true));
       
  2762                 }
       
  2763 
       
  2764                 result.appendChild(((CipherDataImpl) super.getCipherData()).toElement());
       
  2765                 if (null != super.getEncryptionProperties()) {
       
  2766                     result.appendChild(((EncryptionPropertiesImpl)
       
  2767                         super.getEncryptionProperties()).toElement());
       
  2768                 }
       
  2769 
       
  2770                 return result;
       
  2771             }
       
  2772         }
       
  2773 
       
  2774         private class EncryptedKeyImpl extends EncryptedTypeImpl implements EncryptedKey {
       
  2775             private String keyRecipient = null;
       
  2776             private ReferenceList referenceList = null;
       
  2777             private String carriedName = null;
       
  2778 
       
  2779             /**
       
  2780              * @param data
       
  2781              */
       
  2782             public EncryptedKeyImpl(CipherData data) {
       
  2783                 super(data);
       
  2784             }
       
  2785 
       
  2786             /** @inheritDoc */
       
  2787             public String getRecipient() {
       
  2788                 return keyRecipient;
       
  2789             }
       
  2790 
       
  2791             /** @inheritDoc */
       
  2792             public void setRecipient(String recipient) {
       
  2793                 keyRecipient = recipient;
       
  2794             }
       
  2795 
       
  2796             /** @inheritDoc */
       
  2797             public ReferenceList getReferenceList() {
       
  2798                 return referenceList;
       
  2799             }
       
  2800 
       
  2801             /** @inheritDoc */
       
  2802             public void setReferenceList(ReferenceList list) {
       
  2803                 referenceList = list;
       
  2804             }
       
  2805 
       
  2806             /** @inheritDoc */
       
  2807             public String getCarriedName() {
       
  2808                 return carriedName;
       
  2809             }
       
  2810 
       
  2811             /** @inheritDoc */
       
  2812             public void setCarriedName(String name) {
       
  2813                 carriedName = name;
       
  2814             }
       
  2815 
       
  2816             Element toElement() {
       
  2817                 Element result =
       
  2818                     ElementProxy.createElementForFamily(
       
  2819                         contextDocument, EncryptionConstants.EncryptionSpecNS,
       
  2820                         EncryptionConstants._TAG_ENCRYPTEDKEY
       
  2821                     );
       
  2822 
       
  2823                 if (null != super.getId()) {
       
  2824                     result.setAttributeNS(null, EncryptionConstants._ATT_ID, super.getId());
       
  2825                 }
       
  2826                 if (null != super.getType()) {
       
  2827                     result.setAttributeNS(null, EncryptionConstants._ATT_TYPE, super.getType());
       
  2828                 }
       
  2829                 if (null != super.getMimeType()) {
       
  2830                     result.setAttributeNS(
       
  2831                         null, EncryptionConstants._ATT_MIMETYPE, super.getMimeType()
       
  2832                     );
       
  2833                 }
       
  2834                 if (null != super.getEncoding()) {
       
  2835                     result.setAttributeNS(null, Constants._ATT_ENCODING, super.getEncoding());
       
  2836                 }
       
  2837                 if (null != getRecipient()) {
       
  2838                     result.setAttributeNS(
       
  2839                         null, EncryptionConstants._ATT_RECIPIENT, getRecipient()
       
  2840                     );
       
  2841                 }
       
  2842                 if (null != super.getEncryptionMethod()) {
       
  2843                     result.appendChild(((EncryptionMethodImpl)
       
  2844                         super.getEncryptionMethod()).toElement());
       
  2845                 }
       
  2846                 if (null != super.getKeyInfo()) {
       
  2847                     result.appendChild(super.getKeyInfo().getElement().cloneNode(true));
       
  2848                 }
       
  2849                 result.appendChild(((CipherDataImpl) super.getCipherData()).toElement());
       
  2850                 if (null != super.getEncryptionProperties()) {
       
  2851                     result.appendChild(((EncryptionPropertiesImpl)
       
  2852                         super.getEncryptionProperties()).toElement());
       
  2853                 }
       
  2854                 if (referenceList != null && !referenceList.isEmpty()) {
       
  2855                     result.appendChild(((ReferenceListImpl)getReferenceList()).toElement());
       
  2856                 }
       
  2857                 if (null != carriedName) {
       
  2858                     Element element =
       
  2859                         ElementProxy.createElementForFamily(
       
  2860                             contextDocument,
       
  2861                             EncryptionConstants.EncryptionSpecNS,
       
  2862                             EncryptionConstants._TAG_CARRIEDKEYNAME
       
  2863                         );
       
  2864                     Node node = contextDocument.createTextNode(carriedName);
       
  2865                     element.appendChild(node);
       
  2866                     result.appendChild(element);
       
  2867                 }
       
  2868 
       
  2869                 return result;
       
  2870             }
       
  2871         }
       
  2872 
       
  2873         private abstract class EncryptedTypeImpl {
       
  2874             private String id =  null;
       
  2875             private String type = null;
       
  2876             private String mimeType = null;
       
  2877             private String encoding = null;
       
  2878             private EncryptionMethod encryptionMethod = null;
       
  2879             private KeyInfo keyInfo = null;
       
  2880             private CipherData cipherData = null;
       
  2881             private EncryptionProperties encryptionProperties = null;
       
  2882 
       
  2883             /**
       
  2884              * Constructor.
       
  2885              * @param data
       
  2886              */
       
  2887             protected EncryptedTypeImpl(CipherData data) {
       
  2888                 cipherData = data;
       
  2889             }
       
  2890 
       
  2891             /**
       
  2892              *
       
  2893              * @return the Id
       
  2894              */
       
  2895             public String getId() {
       
  2896                 return id;
       
  2897             }
       
  2898 
       
  2899             /**
       
  2900              *
       
  2901              * @param id
       
  2902              */
       
  2903             public void setId(String id) {
       
  2904                 this.id = id;
       
  2905             }
       
  2906 
       
  2907             /**
       
  2908              *
       
  2909              * @return the type
       
  2910              */
       
  2911             public String getType() {
       
  2912                 return type;
       
  2913             }
       
  2914 
       
  2915             /**
       
  2916              *
       
  2917              * @param type
       
  2918              */
       
  2919             public void setType(String type) {
       
  2920                 if (type == null || type.length() == 0) {
       
  2921                     this.type = null;
       
  2922                 } else {
       
  2923                     URI tmpType = null;
       
  2924                     try {
       
  2925                         tmpType = new URI(type);
       
  2926                     } catch (URISyntaxException ex) {
       
  2927                         throw (IllegalArgumentException)
       
  2928                         new IllegalArgumentException().initCause(ex);
       
  2929                     }
       
  2930                     this.type = tmpType.toString();
       
  2931                 }
       
  2932             }
       
  2933 
       
  2934             /**
       
  2935              *
       
  2936              * @return the MimeType
       
  2937              */
       
  2938             public String getMimeType() {
       
  2939                 return mimeType;
       
  2940             }
       
  2941             /**
       
  2942              *
       
  2943              * @param type
       
  2944              */
       
  2945             public void setMimeType(String type) {
       
  2946                 mimeType = type;
       
  2947             }
       
  2948 
       
  2949             /**
       
  2950              *
       
  2951              * @return the encoding
       
  2952              */
       
  2953             public String getEncoding() {
       
  2954                 return encoding;
       
  2955             }
       
  2956 
       
  2957             /**
       
  2958              *
       
  2959              * @param encoding
       
  2960              */
       
  2961             public void setEncoding(String encoding) {
       
  2962                 if (encoding == null || encoding.length() == 0) {
       
  2963                     this.encoding = null;
       
  2964                 } else {
       
  2965                     URI tmpEncoding = null;
       
  2966                     try {
       
  2967                         tmpEncoding = new URI(encoding);
       
  2968                     } catch (URISyntaxException ex) {
       
  2969                         throw (IllegalArgumentException)
       
  2970                         new IllegalArgumentException().initCause(ex);
       
  2971                     }
       
  2972                     this.encoding = tmpEncoding.toString();
       
  2973                 }
       
  2974             }
       
  2975 
       
  2976             /**
       
  2977              *
       
  2978              * @return the EncryptionMethod
       
  2979              */
       
  2980             public EncryptionMethod getEncryptionMethod() {
       
  2981                 return encryptionMethod;
       
  2982             }
       
  2983 
       
  2984             /**
       
  2985              *
       
  2986              * @param method
       
  2987              */
       
  2988             public void setEncryptionMethod(EncryptionMethod method) {
       
  2989                 encryptionMethod = method;
       
  2990             }
       
  2991 
       
  2992             /**
       
  2993              *
       
  2994              * @return the KeyInfo
       
  2995              */
       
  2996             public KeyInfo getKeyInfo() {
       
  2997                 return keyInfo;
       
  2998             }
       
  2999 
       
  3000             /**
       
  3001              *
       
  3002              * @param info
       
  3003              */
       
  3004             public void setKeyInfo(KeyInfo info) {
       
  3005                 keyInfo = info;
       
  3006             }
       
  3007 
       
  3008             /**
       
  3009              *
       
  3010              * @return the CipherData
       
  3011              */
       
  3012             public CipherData getCipherData() {
       
  3013                 return cipherData;
       
  3014             }
       
  3015 
       
  3016             /**
       
  3017              *
       
  3018              * @return the EncryptionProperties
       
  3019              */
       
  3020             public EncryptionProperties getEncryptionProperties() {
       
  3021                 return encryptionProperties;
       
  3022             }
       
  3023 
       
  3024             /**
       
  3025              *
       
  3026              * @param properties
       
  3027              */
       
  3028             public void setEncryptionProperties(EncryptionProperties properties) {
       
  3029                 encryptionProperties = properties;
       
  3030             }
       
  3031         }
       
  3032 
       
  3033         private class EncryptionMethodImpl implements EncryptionMethod {
       
  3034             private String algorithm = null;
       
  3035             private int keySize = Integer.MIN_VALUE;
       
  3036             private byte[] oaepParams = null;
       
  3037             private List<Element> encryptionMethodInformation = null;
       
  3038             private String digestAlgorithm = null;
       
  3039             private String mgfAlgorithm = null;
       
  3040 
       
  3041             /**
       
  3042              * Constructor.
       
  3043              * @param algorithm
       
  3044              */
       
  3045             public EncryptionMethodImpl(String algorithm) {
       
  3046                 URI tmpAlgorithm = null;
       
  3047                 try {
       
  3048                     tmpAlgorithm = new URI(algorithm);
       
  3049                 } catch (URISyntaxException ex) {
       
  3050                     throw (IllegalArgumentException)
       
  3051                     new IllegalArgumentException().initCause(ex);
       
  3052                 }
       
  3053                 this.algorithm = tmpAlgorithm.toString();
       
  3054                 encryptionMethodInformation = new LinkedList<Element>();
       
  3055             }
       
  3056 
       
  3057             /** @inheritDoc */
       
  3058             public String getAlgorithm() {
       
  3059                 return algorithm;
       
  3060             }
       
  3061 
       
  3062             /** @inheritDoc */
       
  3063             public int getKeySize() {
       
  3064                 return keySize;
       
  3065             }
       
  3066 
       
  3067             /** @inheritDoc */
       
  3068             public void setKeySize(int size) {
       
  3069                 keySize = size;
       
  3070             }
       
  3071 
       
  3072             /** @inheritDoc */
       
  3073             public byte[] getOAEPparams() {
       
  3074                 return oaepParams;
       
  3075             }
       
  3076 
       
  3077             /** @inheritDoc */
       
  3078             public void setOAEPparams(byte[] params) {
       
  3079                 oaepParams = params;
       
  3080             }
       
  3081 
       
  3082             /** @inheritDoc */
       
  3083             public void setDigestAlgorithm(String digestAlgorithm) {
       
  3084                 this.digestAlgorithm = digestAlgorithm;
       
  3085             }
       
  3086 
       
  3087             /** @inheritDoc */
       
  3088             public String getDigestAlgorithm() {
       
  3089                 return digestAlgorithm;
       
  3090             }
       
  3091 
       
  3092             /** @inheritDoc */
       
  3093             public void setMGFAlgorithm(String mgfAlgorithm) {
       
  3094                 this.mgfAlgorithm = mgfAlgorithm;
       
  3095             }
       
  3096 
       
  3097             /** @inheritDoc */
       
  3098             public String getMGFAlgorithm() {
       
  3099                 return mgfAlgorithm;
       
  3100             }
       
  3101 
       
  3102             /** @inheritDoc */
       
  3103             public Iterator<Element> getEncryptionMethodInformation() {
       
  3104                 return encryptionMethodInformation.iterator();
       
  3105             }
       
  3106 
       
  3107             /** @inheritDoc */
       
  3108             public void addEncryptionMethodInformation(Element info) {
       
  3109                 encryptionMethodInformation.add(info);
       
  3110             }
       
  3111 
       
  3112             /** @inheritDoc */
       
  3113             public void removeEncryptionMethodInformation(Element info) {
       
  3114                 encryptionMethodInformation.remove(info);
       
  3115             }
       
  3116 
       
  3117             Element toElement() {
       
  3118                 Element result =
       
  3119                     XMLUtils.createElementInEncryptionSpace(
       
  3120                         contextDocument, EncryptionConstants._TAG_ENCRYPTIONMETHOD
       
  3121                     );
       
  3122                 result.setAttributeNS(null, EncryptionConstants._ATT_ALGORITHM, algorithm);
       
  3123                 if (keySize > 0) {
       
  3124                     result.appendChild(
       
  3125                         XMLUtils.createElementInEncryptionSpace(
       
  3126                             contextDocument, EncryptionConstants._TAG_KEYSIZE
       
  3127                     ).appendChild(contextDocument.createTextNode(String.valueOf(keySize))));
       
  3128                 }
       
  3129                 if (null != oaepParams) {
       
  3130                     Element oaepElement =
       
  3131                         XMLUtils.createElementInEncryptionSpace(
       
  3132                             contextDocument, EncryptionConstants._TAG_OAEPPARAMS
       
  3133                         );
       
  3134                     oaepElement.appendChild(contextDocument.createTextNode(Base64.encode(oaepParams)));
       
  3135                     result.appendChild(oaepElement);
       
  3136                 }
       
  3137                 if (digestAlgorithm != null) {
       
  3138                     Element digestElement =
       
  3139                         XMLUtils.createElementInSignatureSpace(contextDocument, Constants._TAG_DIGESTMETHOD);
       
  3140                     digestElement.setAttributeNS(null, "Algorithm", digestAlgorithm);
       
  3141                     result.appendChild(digestElement);
       
  3142                 }
       
  3143                 if (mgfAlgorithm != null) {
       
  3144                     Element mgfElement =
       
  3145                         XMLUtils.createElementInEncryption11Space(
       
  3146                             contextDocument, EncryptionConstants._TAG_MGF
       
  3147                         );
       
  3148                     mgfElement.setAttributeNS(null, "Algorithm", mgfAlgorithm);
       
  3149                     mgfElement.setAttributeNS(
       
  3150                         Constants.NamespaceSpecNS,
       
  3151                         "xmlns:" + ElementProxy.getDefaultPrefix(EncryptionConstants.EncryptionSpec11NS),
       
  3152                         EncryptionConstants.EncryptionSpec11NS
       
  3153                     );
       
  3154                     result.appendChild(mgfElement);
       
  3155                 }
       
  3156                 Iterator<Element> itr = encryptionMethodInformation.iterator();
       
  3157                 while (itr.hasNext()) {
       
  3158                     result.appendChild(itr.next());
       
  3159                 }
       
  3160 
       
  3161                 return result;
       
  3162             }
       
  3163         }
       
  3164 
       
  3165         private class EncryptionPropertiesImpl implements EncryptionProperties {
       
  3166             private String id = null;
       
  3167             private List<EncryptionProperty> encryptionProperties = null;
       
  3168 
       
  3169             /**
       
  3170              * Constructor.
       
  3171              */
       
  3172             public EncryptionPropertiesImpl() {
       
  3173                 encryptionProperties = new LinkedList<EncryptionProperty>();
       
  3174             }
       
  3175 
       
  3176             /** @inheritDoc */
       
  3177             public String getId() {
       
  3178                 return id;
       
  3179             }
       
  3180 
       
  3181             /** @inheritDoc */
       
  3182             public void setId(String id) {
       
  3183                 this.id = id;
       
  3184             }
       
  3185 
       
  3186             /** @inheritDoc */
       
  3187             public Iterator<EncryptionProperty> getEncryptionProperties() {
       
  3188                 return encryptionProperties.iterator();
       
  3189             }
       
  3190 
       
  3191             /** @inheritDoc */
       
  3192             public void addEncryptionProperty(EncryptionProperty property) {
       
  3193                 encryptionProperties.add(property);
       
  3194             }
       
  3195 
       
  3196             /** @inheritDoc */
       
  3197             public void removeEncryptionProperty(EncryptionProperty property) {
       
  3198                 encryptionProperties.remove(property);
       
  3199             }
       
  3200 
       
  3201             Element toElement() {
       
  3202                 Element result =
       
  3203                     XMLUtils.createElementInEncryptionSpace(
       
  3204                         contextDocument, EncryptionConstants._TAG_ENCRYPTIONPROPERTIES
       
  3205                     );
       
  3206                 if (null != id) {
       
  3207                     result.setAttributeNS(null, EncryptionConstants._ATT_ID, id);
       
  3208                 }
       
  3209                 Iterator<EncryptionProperty> itr = getEncryptionProperties();
       
  3210                 while (itr.hasNext()) {
       
  3211                     result.appendChild(((EncryptionPropertyImpl)itr.next()).toElement());
       
  3212                 }
       
  3213 
       
  3214                 return result;
       
  3215             }
       
  3216         }
       
  3217 
       
  3218         private class EncryptionPropertyImpl implements EncryptionProperty {
       
  3219             private String target = null;
       
  3220             private String id = null;
       
  3221             private Map<String, String> attributeMap = new HashMap<String, String>();
       
  3222             private List<Element> encryptionInformation = null;
       
  3223 
       
  3224             /**
       
  3225              * Constructor.
       
  3226              */
       
  3227             public EncryptionPropertyImpl() {
       
  3228                 encryptionInformation = new LinkedList<Element>();
       
  3229             }
       
  3230 
       
  3231             /** @inheritDoc */
       
  3232             public String getTarget() {
       
  3233                 return target;
       
  3234             }
       
  3235 
       
  3236             /** @inheritDoc */
       
  3237             public void setTarget(String target) {
       
  3238                 if (target == null || target.length() == 0) {
       
  3239                     this.target = null;
       
  3240                 } else if (target.startsWith("#")) {
       
  3241                     /*
       
  3242                      * This is a same document URI reference. Do not parse,
       
  3243                      * because it has no scheme.
       
  3244                      */
       
  3245                     this.target = target;
       
  3246                 } else {
       
  3247                     URI tmpTarget = null;
       
  3248                     try {
       
  3249                         tmpTarget = new URI(target);
       
  3250                     } catch (URISyntaxException ex) {
       
  3251                         throw (IllegalArgumentException)
       
  3252                         new IllegalArgumentException().initCause(ex);
       
  3253                     }
       
  3254                     this.target = tmpTarget.toString();
       
  3255                 }
       
  3256             }
       
  3257 
       
  3258             /** @inheritDoc */
       
  3259             public String getId() {
       
  3260                 return id;
       
  3261             }
       
  3262 
       
  3263             /** @inheritDoc */
       
  3264             public void setId(String id) {
       
  3265                 this.id = id;
       
  3266             }
       
  3267 
       
  3268             /** @inheritDoc */
       
  3269             public String getAttribute(String attribute) {
       
  3270                 return attributeMap.get(attribute);
       
  3271             }
       
  3272 
       
  3273             /** @inheritDoc */
       
  3274             public void setAttribute(String attribute, String value) {
       
  3275                 attributeMap.put(attribute, value);
       
  3276             }
       
  3277 
       
  3278             /** @inheritDoc */
       
  3279             public Iterator<Element> getEncryptionInformation() {
       
  3280                 return encryptionInformation.iterator();
       
  3281             }
       
  3282 
       
  3283             /** @inheritDoc */
       
  3284             public void addEncryptionInformation(Element info) {
       
  3285                 encryptionInformation.add(info);
       
  3286             }
       
  3287 
       
  3288             /** @inheritDoc */
       
  3289             public void removeEncryptionInformation(Element info) {
       
  3290                 encryptionInformation.remove(info);
       
  3291             }
       
  3292 
       
  3293             Element toElement() {
       
  3294                 Element result =
       
  3295                     XMLUtils.createElementInEncryptionSpace(
       
  3296                         contextDocument, EncryptionConstants._TAG_ENCRYPTIONPROPERTY
       
  3297                     );
       
  3298                 if (null != target) {
       
  3299                     result.setAttributeNS(null, EncryptionConstants._ATT_TARGET, target);
       
  3300                 }
       
  3301                 if (null != id) {
       
  3302                     result.setAttributeNS(null, EncryptionConstants._ATT_ID, id);
       
  3303                 }
       
  3304                 // TODO: figure out the anyAttribyte stuff...
       
  3305                 // TODO: figure out the any stuff...
       
  3306 
       
  3307                 return result;
       
  3308             }
       
  3309         }
       
  3310 
       
  3311         private class TransformsImpl extends com.sun.org.apache.xml.internal.security.transforms.Transforms
       
  3312             implements Transforms {
       
  3313 
       
  3314             /**
       
  3315              * Construct Transforms
       
  3316              */
       
  3317             public TransformsImpl() {
       
  3318                 super(contextDocument);
       
  3319             }
       
  3320 
       
  3321             /**
       
  3322              *
       
  3323              * @param doc
       
  3324              */
       
  3325             public TransformsImpl(Document doc) {
       
  3326                 if (doc == null) {
       
  3327                     throw new RuntimeException("Document is null");
       
  3328                 }
       
  3329 
       
  3330                 this.doc = doc;
       
  3331                 this.constructionElement =
       
  3332                     createElementForFamilyLocal(
       
  3333                         this.doc, this.getBaseNamespace(), this.getBaseLocalName()
       
  3334                     );
       
  3335             }
       
  3336 
       
  3337             /**
       
  3338              *
       
  3339              * @param element
       
  3340              * @throws XMLSignatureException
       
  3341              * @throws InvalidTransformException
       
  3342              * @throws XMLSecurityException
       
  3343              * @throws TransformationException
       
  3344              */
       
  3345             public TransformsImpl(Element element)
       
  3346                 throws XMLSignatureException, InvalidTransformException,
       
  3347                     XMLSecurityException, TransformationException {
       
  3348                 super(element, "");
       
  3349             }
       
  3350 
       
  3351             /**
       
  3352              *
       
  3353              * @return the XML Element form of that Transforms
       
  3354              */
       
  3355             public Element toElement() {
       
  3356                 if (doc == null) {
       
  3357                     doc = contextDocument;
       
  3358                 }
       
  3359 
       
  3360                 return getElement();
       
  3361             }
       
  3362 
       
  3363             /** @inheritDoc */
       
  3364             public com.sun.org.apache.xml.internal.security.transforms.Transforms getDSTransforms() {
       
  3365                 return this;
       
  3366             }
       
  3367 
       
  3368             // Over-ride the namespace
       
  3369             /** @inheritDoc */
       
  3370             public String getBaseNamespace() {
       
  3371                 return EncryptionConstants.EncryptionSpecNS;
       
  3372             }
       
  3373         }
       
  3374 
       
  3375         private class ReferenceListImpl implements ReferenceList {
       
  3376             private Class<?> sentry;
       
  3377             private List<Reference> references;
       
  3378 
       
  3379             /**
       
  3380              * Constructor.
       
  3381              * @param type
       
  3382              */
       
  3383             public ReferenceListImpl(int type) {
       
  3384                 if (type == ReferenceList.DATA_REFERENCE) {
       
  3385                     sentry = DataReference.class;
       
  3386                 } else if (type == ReferenceList.KEY_REFERENCE) {
       
  3387                     sentry = KeyReference.class;
       
  3388                 } else {
       
  3389                     throw new IllegalArgumentException();
       
  3390                 }
       
  3391                 references = new LinkedList<Reference>();
       
  3392             }
       
  3393 
       
  3394             /** @inheritDoc */
       
  3395             public void add(Reference reference) {
       
  3396                 if (!reference.getClass().equals(sentry)) {
       
  3397                     throw new IllegalArgumentException();
       
  3398                 }
       
  3399                 references.add(reference);
       
  3400             }
       
  3401 
       
  3402             /** @inheritDoc */
       
  3403             public void remove(Reference reference) {
       
  3404                 if (!reference.getClass().equals(sentry)) {
       
  3405                     throw new IllegalArgumentException();
       
  3406                 }
       
  3407                 references.remove(reference);
       
  3408             }
       
  3409 
       
  3410             /** @inheritDoc */
       
  3411             public int size() {
       
  3412                 return references.size();
       
  3413             }
       
  3414 
       
  3415             /** @inheritDoc */
       
  3416             public boolean isEmpty() {
       
  3417                 return references.isEmpty();
       
  3418             }
       
  3419 
       
  3420             /** @inheritDoc */
       
  3421             public Iterator<Reference> getReferences() {
       
  3422                 return references.iterator();
       
  3423             }
       
  3424 
       
  3425             Element toElement() {
       
  3426                 Element result =
       
  3427                     ElementProxy.createElementForFamily(
       
  3428                         contextDocument,
       
  3429                         EncryptionConstants.EncryptionSpecNS,
       
  3430                         EncryptionConstants._TAG_REFERENCELIST
       
  3431                     );
       
  3432                 Iterator<Reference> eachReference = references.iterator();
       
  3433                 while (eachReference.hasNext()) {
       
  3434                     Reference reference = eachReference.next();
       
  3435                     result.appendChild(((ReferenceImpl) reference).toElement());
       
  3436                 }
       
  3437                 return result;
       
  3438             }
       
  3439 
       
  3440             /** @inheritDoc */
       
  3441             public Reference newDataReference(String uri) {
       
  3442                 return new DataReference(uri);
       
  3443             }
       
  3444 
       
  3445             /** @inheritDoc */
       
  3446             public Reference newKeyReference(String uri) {
       
  3447                 return new KeyReference(uri);
       
  3448             }
       
  3449 
       
  3450             /**
       
  3451              * <code>ReferenceImpl</code> is an implementation of
       
  3452              * <code>Reference</code>.
       
  3453              *
       
  3454              * @see Reference
       
  3455              */
       
  3456             private abstract class ReferenceImpl implements Reference {
       
  3457                 private String uri;
       
  3458                 private List<Element> referenceInformation;
       
  3459 
       
  3460                 ReferenceImpl(String uri) {
       
  3461                     this.uri = uri;
       
  3462                     referenceInformation = new LinkedList<Element>();
       
  3463                 }
       
  3464 
       
  3465                 /** @inheritDoc */
       
  3466                 public abstract String getType();
       
  3467 
       
  3468                 /** @inheritDoc */
       
  3469                 public String getURI() {
       
  3470                     return uri;
       
  3471                 }
       
  3472 
       
  3473                 /** @inheritDoc */
       
  3474                 public Iterator<Element> getElementRetrievalInformation() {
       
  3475                     return referenceInformation.iterator();
       
  3476                 }
       
  3477 
       
  3478                 /** @inheritDoc */
       
  3479                 public void setURI(String uri) {
       
  3480                     this.uri = uri;
       
  3481                 }
       
  3482 
       
  3483                 /** @inheritDoc */
       
  3484                 public void removeElementRetrievalInformation(Element node) {
       
  3485                     referenceInformation.remove(node);
       
  3486                 }
       
  3487 
       
  3488                 /** @inheritDoc */
       
  3489                 public void addElementRetrievalInformation(Element node) {
       
  3490                     referenceInformation.add(node);
       
  3491                 }
       
  3492 
       
  3493                 /**
       
  3494                  * @return the XML Element form of that Reference
       
  3495                  */
       
  3496                 public Element toElement() {
       
  3497                     String tagName = getType();
       
  3498                     Element result =
       
  3499                         ElementProxy.createElementForFamily(
       
  3500                             contextDocument,
       
  3501                             EncryptionConstants.EncryptionSpecNS,
       
  3502                             tagName
       
  3503                         );
       
  3504                     result.setAttribute(EncryptionConstants._ATT_URI, uri);
       
  3505 
       
  3506                     // TODO: Need to martial referenceInformation
       
  3507                     // Figure out how to make this work..
       
  3508                     // <any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
       
  3509 
       
  3510                     return result;
       
  3511                 }
       
  3512             }
       
  3513 
       
  3514             private class DataReference extends ReferenceImpl {
       
  3515 
       
  3516                 DataReference(String uri) {
       
  3517                     super(uri);
       
  3518                 }
       
  3519 
       
  3520                 /** @inheritDoc */
       
  3521                 public String getType() {
       
  3522                     return EncryptionConstants._TAG_DATAREFERENCE;
       
  3523                 }
       
  3524             }
       
  3525 
       
  3526             private class KeyReference extends ReferenceImpl {
       
  3527 
       
  3528                 KeyReference(String uri) {
       
  3529                     super(uri);
       
  3530                 }
       
  3531 
       
  3532                 /** @inheritDoc */
       
  3533                 public String getType() {
       
  3534                     return EncryptionConstants._TAG_KEYREFERENCE;
       
  3535                 }
       
  3536             }
       
  3537         }
       
  3538     }
       
  3539 }