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