KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xml > internal > security > encryption > XMLCipher


1 /*
2  * Copyright 2003-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */

17 package com.sun.org.apache.xml.internal.security.encryption;
18
19
20 import java.io.ByteArrayOutputStream JavaDoc;
21 import java.io.IOException JavaDoc;
22 import java.io.StringReader JavaDoc;
23 import java.io.UnsupportedEncodingException JavaDoc;
24 import java.security.InvalidAlgorithmParameterException JavaDoc;
25 import java.security.InvalidKeyException JavaDoc;
26 import java.security.Key JavaDoc;
27 import java.security.NoSuchAlgorithmException JavaDoc;
28 import java.security.NoSuchProviderException JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.LinkedList JavaDoc;
31 import java.util.List JavaDoc;
32
33 import javax.crypto.BadPaddingException;
34 import javax.crypto.Cipher;
35 import javax.crypto.IllegalBlockSizeException;
36 import javax.crypto.NoSuchPaddingException;
37 import javax.crypto.spec.IvParameterSpec;
38 import javax.xml.parsers.DocumentBuilder JavaDoc;
39 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
40 import javax.xml.parsers.ParserConfigurationException JavaDoc;
41
42 import com.sun.org.apache.xml.internal.security.algorithms.JCEMapper;
43 import com.sun.org.apache.xml.internal.security.algorithms.MessageDigestAlgorithm;
44 import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer;
45 import com.sun.org.apache.xml.internal.security.c14n.InvalidCanonicalizerException;
46 import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException;
47 import com.sun.org.apache.xml.internal.security.keys.KeyInfo;
48 import com.sun.org.apache.xml.internal.security.keys.keyresolver.KeyResolverException;
49 import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.EncryptedKeyResolver;
50 import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException;
51 import com.sun.org.apache.xml.internal.security.transforms.InvalidTransformException;
52 import com.sun.org.apache.xml.internal.security.transforms.TransformationException;
53 import com.sun.org.apache.xml.internal.security.utils.Base64;
54 import com.sun.org.apache.xml.internal.security.utils.Constants;
55 import com.sun.org.apache.xml.internal.security.utils.ElementProxy;
56 import com.sun.org.apache.xml.internal.security.utils.EncryptionConstants;
57 import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
58 import com.sun.org.apache.xml.internal.utils.URI;
59 import org.w3c.dom.Attr JavaDoc;
60 import org.w3c.dom.Document JavaDoc;
61 import org.w3c.dom.DocumentFragment JavaDoc;
62 import org.w3c.dom.Element JavaDoc;
63 import org.w3c.dom.NamedNodeMap JavaDoc;
64 import org.w3c.dom.Node JavaDoc;
65 import org.w3c.dom.NodeList JavaDoc;
66 import org.xml.sax.InputSource JavaDoc;
67 import org.xml.sax.SAXException JavaDoc;
68
69
70 /**
71  * <code>XMLCipher</code> encrypts and decrypts the contents of
72  * <code>Document</code>s, <code>Element</code>s and <code>Element</code>
73  * contents. It was designed to resemble <code>javax.crypto.Cipher</code> in
74  * order to facilitate understanding of its functioning.
75  *
76  * @author Axl Mattheus (Sun Microsystems)
77  * @author Christian Geuer-Pollmann
78  */

79 public class XMLCipher {
80
81     private static java.util.logging.Logger JavaDoc logger =
82         java.util.logging.Logger.getLogger(XMLCipher.class.getName());
83
84     //J-
85
/** Triple DES EDE (192 bit key) in CBC mode */
86     public static final String JavaDoc TRIPLEDES =
87         EncryptionConstants.ALGO_ID_BLOCKCIPHER_TRIPLEDES;
88     /** AES 128 Cipher */
89     public static final String JavaDoc AES_128 =
90         EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128;
91     /** AES 256 Cipher */
92     public static final String JavaDoc AES_256 =
93         EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256;
94     /** AES 192 Cipher */
95     public static final String JavaDoc AES_192 =
96         EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES192;
97     /** RSA 1.5 Cipher */
98     public static final String JavaDoc RSA_v1dot5 =
99         EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSA15;
100     /** RSA OAEP Cipher */
101     public static final String JavaDoc RSA_OAEP =
102         EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSAOAEP;
103     /** DIFFIE_HELLMAN Cipher */
104     public static final String JavaDoc DIFFIE_HELLMAN =
105         EncryptionConstants.ALGO_ID_KEYAGREEMENT_DH;
106     /** Triple DES EDE (192 bit key) in CBC mode KEYWRAP*/
107     public static final String JavaDoc TRIPLEDES_KeyWrap =
108         EncryptionConstants.ALGO_ID_KEYWRAP_TRIPLEDES;
109     /** AES 128 Cipher KeyWrap */
110     public static final String JavaDoc AES_128_KeyWrap =
111         EncryptionConstants.ALGO_ID_KEYWRAP_AES128;
112     /** AES 256 Cipher KeyWrap */
113     public static final String JavaDoc AES_256_KeyWrap =
114         EncryptionConstants.ALGO_ID_KEYWRAP_AES256;
115     /** AES 192 Cipher KeyWrap */
116     public static final String JavaDoc AES_192_KeyWrap =
117         EncryptionConstants.ALGO_ID_KEYWRAP_AES192;
118     /** SHA1 Cipher */
119     public static final String JavaDoc SHA1 =
120         Constants.ALGO_ID_DIGEST_SHA1;
121     /** SHA256 Cipher */
122     public static final String JavaDoc SHA256 =
123         MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA256;
124     /** SHA512 Cipher */
125     public static final String JavaDoc SHA512 =
126         MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA512;
127     /** RIPEMD Cipher */
128     public static final String JavaDoc RIPEMD_160 =
129         MessageDigestAlgorithm.ALGO_ID_DIGEST_RIPEMD160;
130     /** XML Signature NS */
131     public static final String JavaDoc XML_DSIG =
132         Constants.SignatureSpecNS;
133     /** N14C_XML */
134     public static final String JavaDoc N14C_XML =
135         Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS;
136     /** N14C_XML with comments*/
137     public static final String JavaDoc N14C_XML_WITH_COMMENTS =
138         Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS;
139     /** N14C_XML excluisve */
140     public static final String JavaDoc EXCL_XML_N14C =
141         Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS;
142     /** N14C_XML exclusive with commetns*/
143     public static final String JavaDoc EXCL_XML_N14C_WITH_COMMENTS =
144         Canonicalizer.ALGO_ID_C14N_EXCL_WITH_COMMENTS;
145     /** Base64 encoding */
146     public static final String JavaDoc BASE64_ENCODING =
147         com.sun.org.apache.xml.internal.security.transforms.Transforms.TRANSFORM_BASE64_DECODE;
148     //J+
149

150     /** ENCRYPT Mode */
151     public static final int ENCRYPT_MODE = Cipher.ENCRYPT_MODE;
152     /** DECRYPT Mode */
153     public static final int DECRYPT_MODE = Cipher.DECRYPT_MODE;
154     /** UNWRAP Mode */
155     public static final int UNWRAP_MODE = Cipher.UNWRAP_MODE;
156     /** WRAP Mode */
157     public static final int WRAP_MODE = Cipher.WRAP_MODE;
158     
159     private static final String JavaDoc ENC_ALGORITHMS = TRIPLEDES + "\n" +
160         AES_128 + "\n" + AES_256 + "\n" + AES_192 + "\n" + RSA_v1dot5 + "\n" +
161         RSA_OAEP + "\n" + TRIPLEDES_KeyWrap + "\n" + AES_128_KeyWrap + "\n" +
162         AES_256_KeyWrap + "\n" + AES_192_KeyWrap+ "\n";
163     
164     /** Cipher created during initialisation that is used for encryption */
165     private Cipher _contextCipher;
166     /** Mode that the XMLCipher object is operating in */
167     private int _cipherMode = Integer.MIN_VALUE;
168     /** URI of algorithm that is being used for cryptographic operation */
169     private String JavaDoc _algorithm = null;
170     /** Cryptographic provider requested by caller */
171     private String JavaDoc _requestedJCEProvider = null;
172     /** Holds c14n to serialize, if initialized then _always_ use this c14n to serialize */
173     private Canonicalizer _canon;
174     /** Used for creation of DOM nodes in WRAP and ENCRYPT modes */
175     private Document JavaDoc _contextDocument;
176     /** Instance of factory used to create XML Encryption objects */
177     private Factory JavaDoc _factory;
178     /** Internal serializer class for going to/from UTF-8 */
179     private Serializer _serializer;
180
181     /** Local copy of user's key */
182     private Key JavaDoc _key;
183     /** Local copy of the kek (used to decrypt EncryptedKeys during a
184      * DECRYPT_MODE operation */

185     private Key JavaDoc _kek;
186
187     // The EncryptedKey being built (part of a WRAP operation) or read
188
// (part of an UNWRAP operation)
189

190     private EncryptedKey _ek;
191
192     // The EncryptedData being built (part of a WRAP operation) or read
193
// (part of an UNWRAP operation)
194

195     private EncryptedData _ed;
196
197     /**
198      * Creates a new <code>XMLCipher</code>.
199      *
200      * @since 1.0.
201      */

202     private XMLCipher() {
203         if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Constructing XMLCipher...");
204
205         _factory = new Factory JavaDoc();
206         _serializer = new Serializer();
207
208     }
209
210     /**
211      * Checks to ensure that the supplied algorithm is valid.
212      *
213      * @param algorithm the algorithm to check.
214      * @return true if the algorithm is valid, otherwise false.
215      * @since 1.0.
216      */

217     private static boolean isValidEncryptionAlgorithm(String JavaDoc algorithm) {
218         boolean result = (
219             algorithm.equals(TRIPLEDES) ||
220             algorithm.equals(AES_128) ||
221             algorithm.equals(AES_256) ||
222             algorithm.equals(AES_192) ||
223             algorithm.equals(RSA_v1dot5) ||
224             algorithm.equals(RSA_OAEP) ||
225             algorithm.equals(TRIPLEDES_KeyWrap) ||
226             algorithm.equals(AES_128_KeyWrap) ||
227             algorithm.equals(AES_256_KeyWrap) ||
228             algorithm.equals(AES_192_KeyWrap)
229         );
230
231         return (result);
232     }
233
234     /**
235      * Returns an <code>XMLCipher</code> that implements the specified
236      * transformation and operates on the specified context document.
237      * <p>
238      * If the default provider package supplies an implementation of the
239      * requested transformation, an instance of Cipher containing that
240      * implementation is returned. If the transformation is not available in
241      * the default provider package, other provider packages are searched.
242      * <p>
243      * <b>NOTE<sub>1</sub>:</b> The transformation name does not follow the same
244      * pattern as that oulined in the Java Cryptography Extension Reference
245      * Guide but rather that specified by the XML Encryption Syntax and
246      * Processing document. The rational behind this is to make it easier for a
247      * novice at writing Java Encryption software to use the library.
248      * <p>
249      * <b>NOTE<sub>2</sub>:</b> <code>getInstance()</code> does not follow the
250      * same pattern regarding exceptional conditions as that used in
251      * <code>javax.crypto.Cipher</code>. Instead, it only throws an
252      * <code>XMLEncryptionException</code> which wraps an underlying exception.
253      * The stack trace from the exception should be self explanitory.
254      *
255      * @param transformation the name of the transformation, e.g.,
256      * <code>XMLCipher.TRIPLEDES</code> which is shorthand for
257      * &quot;http://www.w3.org/2001/04/xmlenc#tripledes-cbc&quot;
258      * @throws XMLEncryptionException
259      * @return the XMLCipher
260      * @see javax.crypto.Cipher#getInstance(java.lang.String)
261      */

262     public static XMLCipher getInstance(String JavaDoc transformation) throws
263             XMLEncryptionException {
264         // sanity checks
265
if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Getting XMLCipher...");
266         if (null == transformation)
267             logger.log(java.util.logging.Level.SEVERE, "Transformation unexpectedly null...");
268         if(!isValidEncryptionAlgorithm(transformation))
269             logger.log(java.util.logging.Level.WARNING, "Algorithm non-standard, expected one of " + ENC_ALGORITHMS);
270
271         XMLCipher instance = new XMLCipher();
272
273         instance._algorithm = transformation;
274         instance._key = null;
275         instance._kek = null;
276
277
278         /* Create a canonicaliser - used when serialising DOM to octets
279          * prior to encryption (and for the reverse) */

280
281         try {
282             instance._canon = Canonicalizer.getInstance
283                 (Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS);
284             
285         } catch (InvalidCanonicalizerException ice) {
286             throw new XMLEncryptionException("empty", ice);
287         }
288
289         String JavaDoc jceAlgorithm = JCEMapper.translateURItoJCEID(transformation);
290
291         try {
292             instance._contextCipher = Cipher.getInstance(jceAlgorithm);
293             if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "cihper.algoritm = " +
294                 instance._contextCipher.getAlgorithm());
295         } catch (NoSuchAlgorithmException JavaDoc nsae) {
296             throw new XMLEncryptionException("empty", nsae);
297         } catch (NoSuchPaddingException nspe) {
298             throw new XMLEncryptionException("empty", nspe);
299         }
300
301         return (instance);
302     }
303
304     public static XMLCipher getInstance(String JavaDoc transformation,Cipher cipher) throws
305             XMLEncryptionException {
306         // sanity checks
307
logger.log(java.util.logging.Level.FINE, "Getting XMLCipher...");
308         if (null == transformation)
309             logger.log(java.util.logging.Level.SEVERE, "Transformation unexpectedly null...");
310         if(!isValidEncryptionAlgorithm(transformation))
311             logger.log(java.util.logging.Level.WARNING, "Algorithm non-standard, expected one of " + ENC_ALGORITHMS);
312         
313         XMLCipher instance = new XMLCipher();
314         
315         instance._algorithm = transformation;
316         instance._key = null;
317         instance._kek = null;
318         
319         
320                 /* Create a canonicaliser - used when serialising DOM to octets
321                  * prior to encryption (and for the reverse) */

322         
323         try {
324             instance._canon = Canonicalizer.getInstance
325                     (Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS);
326             
327         } catch (InvalidCanonicalizerException ice) {
328             throw new XMLEncryptionException("empty", ice);
329         }
330         
331         String JavaDoc jceAlgorithm = JCEMapper.translateURItoJCEID(transformation);
332         
333         try {
334             instance._contextCipher = cipher;
335             //Cipher.getInstance(jceAlgorithm);
336
logger.log(java.util.logging.Level.FINE, "cihper.algoritm = " +
337                     instance._contextCipher.getAlgorithm());
338         }catch(Exception JavaDoc ex) {
339             throw new XMLEncryptionException("empty", ex);
340         }
341         
342         return (instance);
343     }
344     
345
346
347     /**
348      * Returns an <code>XMLCipher</code> that implements the specified
349      * transformation, operates on the specified context document and serializes
350      * the document with the specified canonicalization algorithm before it
351      * encrypts the document.
352      * <p>
353      *
354      * @param transformation the name of the transformation, e.g.,
355      * <code>XMLCipher.TRIPLEDES</code> which is
356      * shorthand for
357      * &quot;http://www.w3.org/2001/04/xmlenc#tripledes-cbc&quot;
358      * @param canon the name of the c14n algorithm, if
359      * <code>null</code> use standard serializer
360      * @return
361      * @throws XMLEncryptionException
362      */

363
364     public static XMLCipher getInstance(String JavaDoc transformation, String JavaDoc canon)
365         throws XMLEncryptionException {
366         XMLCipher instance = XMLCipher.getInstance(transformation);
367
368         if (canon != null) {
369             try {
370                 instance._canon = Canonicalizer.getInstance(canon);
371             } catch (InvalidCanonicalizerException ice) {
372                 throw new XMLEncryptionException("empty", ice);
373             }
374         }
375
376         return instance;
377     }
378
379
380     /**
381      * Returns an <code>XMLCipher</code> that implements the specified
382      * transformation and operates on the specified context document.
383      *
384      * @param transformation the name of the transformation, e.g.,
385      * <code>XMLCipher.TRIPLEDES</code> which is shorthand for
386      * &quot;http://www.w3.org/2001/04/xmlenc#tripledes-cbc&quot;
387      * @param provider the JCE provider that supplies the transformation
388      * @return the XMLCipher
389      * @throws XMLEncryptionException
390      */

391
392     public static XMLCipher getProviderInstance(String JavaDoc transformation, String JavaDoc provider)
393             throws XMLEncryptionException {
394         // sanity checks
395
if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Getting XMLCipher...");
396         if (null == transformation)
397             logger.log(java.util.logging.Level.SEVERE, "Transformation unexpectedly null...");
398         if(null == provider)
399             logger.log(java.util.logging.Level.SEVERE, "Provider unexpectedly null..");
400         if("" == provider)
401             logger.log(java.util.logging.Level.SEVERE, "Provider's value unexpectedly not specified...");
402         if(!isValidEncryptionAlgorithm(transformation))
403             logger.log(java.util.logging.Level.WARNING, "Algorithm non-standard, expected one of " + ENC_ALGORITHMS);
404
405         XMLCipher instance = new XMLCipher();
406
407         instance._algorithm = transformation;
408         instance._requestedJCEProvider = provider;
409         instance._key = null;
410         instance._kek = null;
411
412         /* Create a canonicaliser - used when serialising DOM to octets
413          * prior to encryption (and for the reverse) */

414
415         try {
416             instance._canon = Canonicalizer.getInstance
417                 (Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS);
418         } catch (InvalidCanonicalizerException ice) {
419             throw new XMLEncryptionException("empty", ice);
420         }
421
422         try {
423             String JavaDoc jceAlgorithm =
424                 JCEMapper.translateURItoJCEID(transformation);
425
426             instance._contextCipher = Cipher.getInstance(jceAlgorithm, provider);
427
428             if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "cipher._algorithm = " +
429                 instance._contextCipher.getAlgorithm());
430             if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "provider.name = " + provider);
431         } catch (NoSuchAlgorithmException JavaDoc nsae) {
432             throw new XMLEncryptionException("empty", nsae);
433         } catch (NoSuchProviderException JavaDoc nspre) {
434             throw new XMLEncryptionException("empty", nspre);
435         } catch (NoSuchPaddingException nspe) {
436             throw new XMLEncryptionException("empty", nspe);
437         }
438
439         return (instance);
440     }
441     
442     /**
443      * Returns an <code>XMLCipher</code> that implements the specified
444      * transformation, operates on the specified context document and serializes
445      * the document with the specified canonicalization algorithm before it
446      * encrypts the document.
447      * <p>
448      *
449      * @param transformation the name of the transformation, e.g.,
450      * <code>XMLCipher.TRIPLEDES</code> which is
451      * shorthand for
452      * &quot;http://www.w3.org/2001/04/xmlenc#tripledes-cbc&quot;
453      * @param provider the JCE provider that supplies the transformation
454      * @param canon the name of the c14n algorithm, if
455      * <code>null</code> use standard serializer
456      * @return
457      * @throws XMLEncryptionException
458      */

459     public static XMLCipher getProviderInstance(
460         String JavaDoc transformation,
461         String JavaDoc provider,
462         String JavaDoc canon)
463         throws XMLEncryptionException {
464
465         XMLCipher instance = XMLCipher.getProviderInstance(transformation, provider);
466         if (canon != null) {
467             try {
468                 instance._canon = Canonicalizer.getInstance(canon);
469             } catch (InvalidCanonicalizerException ice) {
470                 throw new XMLEncryptionException("empty", ice);
471             }
472         }
473         return instance;
474     }
475
476     /**
477      * Returns an <code>XMLCipher</code> that implements no specific
478      * transformation, and can therefore only be used for decrypt or
479      * unwrap operations where the encryption method is defined in the
480      * <code>EncryptionMethod</code> element.
481      *
482      * @return The XMLCipher
483      * @throws XMLEncryptionException
484      */

485
486     public static XMLCipher getInstance()
487             throws XMLEncryptionException {
488         // sanity checks
489
if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Getting XMLCipher for no transformation...");
490
491         XMLCipher instance = new XMLCipher();
492
493         instance._algorithm = null;
494         instance._requestedJCEProvider = null;
495         instance._key = null;
496         instance._kek = null;
497         instance._contextCipher = null;
498
499         /* Create a canonicaliser - used when serialising DOM to octets
500          * prior to encryption (and for the reverse) */

501
502         try {
503             instance._canon = Canonicalizer.getInstance
504                 (Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS);
505         } catch (InvalidCanonicalizerException ice) {
506             throw new XMLEncryptionException("empty", ice);
507         }
508
509         return (instance);
510     }
511
512     /**
513      * Returns an <code>XMLCipher</code> that implements no specific
514      * transformation, and can therefore only be used for decrypt or
515      * unwrap operations where the encryption method is defined in the
516      * <code>EncryptionMethod</code> element.
517      *
518      * Allows the caller to specify a provider that will be used for
519      * cryptographic operations.
520      *
521      * @param provider the JCE provider that supplies the cryptographic
522      * needs.
523      * @return the XMLCipher
524      * @throws XMLEncryptionException
525      */

526
527     public static XMLCipher getProviderInstance(String JavaDoc provider)
528             throws XMLEncryptionException {
529         // sanity checks
530

531         if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Getting XMLCipher, provider but no transformation");
532         if(null == provider)
533             logger.log(java.util.logging.Level.SEVERE, "Provider unexpectedly null..");
534         if("" == provider)
535             logger.log(java.util.logging.Level.SEVERE, "Provider's value unexpectedly not specified...");
536
537         XMLCipher instance = new XMLCipher();
538
539         instance._algorithm = null;
540         instance._requestedJCEProvider = provider;
541         instance._key = null;
542         instance._kek = null;
543         instance._contextCipher = null;
544
545         try {
546             instance._canon = Canonicalizer.getInstance
547                 (Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS);
548         } catch (InvalidCanonicalizerException ice) {
549             throw new XMLEncryptionException("empty", ice);
550         }
551
552         return (instance);
553     }
554
555     /**
556      * Initializes this cipher with a key.
557      * <p>
558      * The cipher is initialized for one of the following four operations:
559      * encryption, decryption, key wrapping or key unwrapping, depending on the
560      * value of opmode.
561      *
562      * For WRAP and ENCRYPT modes, this also initialises the internal
563      * EncryptedKey or EncryptedData (with a CipherValue)
564      * structure that will be used during the ensuing operations. This
565      * can be obtained (in order to modify KeyInfo elements etc. prior to
566      * finalising the encryption) by calling
567      * {@link #getEncryptedData} or {@link #getEncryptedKey}.
568      *
569      * @param opmode the operation mode of this cipher (this is one of the
570      * following: ENCRYPT_MODE, DECRYPT_MODE, WRAP_MODE or UNWRAP_MODE)
571      * @param key
572      * @see javax.crypto.Cipher#init(int, java.security.Key)
573      * @throws XMLEncryptionException
574      */

575     public void init(int opmode, Key JavaDoc key) throws XMLEncryptionException {
576         // sanity checks
577
if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Initializing XMLCipher...");
578
579         _ek = null;
580         _ed = null;
581
582         switch (opmode) {
583
584         case ENCRYPT_MODE :
585             if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "opmode = ENCRYPT_MODE");
586             _ed = createEncryptedData(CipherData.VALUE_TYPE, "NO VALUE YET");
587             break;
588         case DECRYPT_MODE :
589             if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "opmode = DECRYPT_MODE");
590             break;
591         case WRAP_MODE :
592             if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "opmode = WRAP_MODE");
593             _ek = createEncryptedKey(CipherData.VALUE_TYPE, "NO VALUE YET");
594             break;
595         case UNWRAP_MODE :
596             if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "opmode = UNWRAP_MODE");
597             break;
598         default :
599             logger.log(java.util.logging.Level.SEVERE, "Mode unexpectedly invalid");
600             throw new XMLEncryptionException("Invalid mode in init");
601         }
602
603         _cipherMode = opmode;
604         _key = key;
605
606     }
607
608     /**
609      * Get the EncryptedData being build
610      *
611      * Returns the EncryptedData being built during an ENCRYPT operation.
612      * This can then be used by applications to add KeyInfo elements and
613      * set other parameters.
614      *
615      * @return The EncryptedData being built
616      */

617
618     public EncryptedData getEncryptedData() {
619
620         // Sanity checks
621
if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Returning EncryptedData");
622         return _ed;
623
624     }
625
626     /**
627      * Get the EncryptedData being build
628      *
629      * Returns the EncryptedData being built during an ENCRYPT operation.
630      * This can then be used by applications to add KeyInfo elements and
631      * set other parameters.
632      *
633      * @return The EncryptedData being built
634      */

635
636     public EncryptedKey getEncryptedKey() {
637
638         // Sanity checks
639
if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Returning EncryptedKey");
640         return _ek;
641     }
642
643     /**
644      * Set a Key Encryption Key.
645      * <p>
646      * The Key Encryption Key (KEK) is used for encrypting/decrypting
647      * EncryptedKey elements. By setting this separately, the XMLCipher
648      * class can know whether a key applies to the data part or wrapped key
649      * part of an encrypted object.
650      *
651      * @param kek The key to use for de/encrypting key data
652      */

653
654     public void setKEK(Key JavaDoc kek) {
655
656         _kek = kek;
657
658     }
659
660     /**
661      * Martial an EncryptedData
662      *
663      * Takes an EncryptedData object and returns a DOM Element that
664      * represents the appropriate <code>EncryptedData</code>
665      * <p>
666      * <b>Note:</b> This should only be used in cases where the context
667      * document has been passed in via a call to doFinal.
668      *
669      * @param encryptedData EncryptedData object to martial
670      * @return the DOM <code>Element</code> representing the passed in
671      * object
672      */

673
674     public Element JavaDoc martial(EncryptedData encryptedData) {
675
676         return (_factory.toElement (encryptedData));
677
678     }
679
680     /**
681      * Martial an EncryptedKey
682      *
683      * Takes an EncryptedKey object and returns a DOM Element that
684      * represents the appropriate <code>EncryptedKey</code>
685      *
686      * <p>
687      * <b>Note:</b> This should only be used in cases where the context
688      * document has been passed in via a call to doFinal.
689      *
690      * @param encryptedKey EncryptedKey object to martial
691      * @return the DOM <code>Element</code> representing the passed in
692      * object */

693
694     public Element JavaDoc martial(EncryptedKey encryptedKey) {
695
696         return (_factory.toElement (encryptedKey));
697
698     }
699
700     /**
701      * Martial an EncryptedData
702      *
703      * Takes an EncryptedData object and returns a DOM Element that
704      * represents the appropriate <code>EncryptedData</code>
705      *
706      * @param context The document that will own the returned nodes
707      * @param encryptedData EncryptedData object to martial
708      * @return the DOM <code>Element</code> representing the passed in
709      * object */

710
711     public Element JavaDoc martial(Document JavaDoc context, EncryptedData encryptedData) {
712
713         _contextDocument = context;
714         return (_factory.toElement (encryptedData));
715
716     }
717
718     /**
719      * Martial an EncryptedKey
720      *
721      * Takes an EncryptedKey object and returns a DOM Element that
722      * represents the appropriate <code>EncryptedKey</code>
723      *
724      * @param context The document that will own the created nodes
725      * @param encryptedKey EncryptedKey object to martial
726      * @return the DOM <code>Element</code> representing the passed in
727      * object */

728
729     public Element JavaDoc martial(Document JavaDoc context, EncryptedKey encryptedKey) {
730
731         _contextDocument = context;
732         return (_factory.toElement (encryptedKey));
733
734     }
735
736     /**
737      * Encrypts an <code>Element</code> and replaces it with its encrypted
738      * counterpart in the context <code>Document</code>, that is, the
739      * <code>Document</code> specified when one calls
740      * {@link #getInstance(String) getInstance}.
741      *
742      * @param element the <code>Element</code> to encrypt.
743      * @return the context <code>Document</code> with the encrypted
744      * <code>Element</code> having replaced the source <code>Element</code>.
745      * @throws Exception
746      */

747
748     private Document JavaDoc encryptElement(Element JavaDoc element) throws Exception JavaDoc{
749         if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypting element...");
750         if(null == element)
751             logger.log(java.util.logging.Level.SEVERE, "Element unexpectedly null...");
752         if(_cipherMode != ENCRYPT_MODE)
753             if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in ENCRYPT_MODE...");
754
755         if (_algorithm == null) {
756             throw new XMLEncryptionException("XMLCipher instance without transformation specified");
757         }
758         encryptData(_contextDocument, element, false);
759
760         Element JavaDoc encryptedElement = _factory.toElement(_ed);
761
762         Node JavaDoc sourceParent = element.getParentNode();
763         sourceParent.replaceChild(encryptedElement, element);
764
765         return (_contextDocument);
766     }
767
768     /**
769      * Encrypts a <code>NodeList</code> (the contents of an
770      * <code>Element</code>) and replaces its parent <code>Element</code>'s
771      * content with this the resulting <code>EncryptedType</code> within the
772      * context <code>Document</code>, that is, the <code>Document</code>
773      * specified when one calls
774      * {@link #getInstance(String) getInstance}.
775      *
776      * @param element the <code>NodeList</code> to encrypt.
777      * @return the context <code>Document</code> with the encrypted
778      * <code>NodeList</code> having replaced the content of the source
779      * <code>Element</code>.
780      * @throws Exception
781      */

782     private Document JavaDoc encryptElementContent(Element JavaDoc element) throws
783             /* XMLEncryption */Exception JavaDoc {
784