• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17 
18 package javax.crypto;
19 
20 import java.nio.ByteBuffer;
21 import java.security.AlgorithmParameters;
22 import java.security.InvalidAlgorithmParameterException;
23 import java.security.InvalidKeyException;
24 import java.security.InvalidParameterException;
25 import java.security.Key;
26 import java.security.NoSuchAlgorithmException;
27 import java.security.NoSuchProviderException;
28 import java.security.Provider;
29 import java.security.SecureRandom;
30 import java.security.Security;
31 import java.security.cert.Certificate;
32 import java.security.cert.X509Certificate;
33 import java.security.spec.AlgorithmParameterSpec;
34 import java.util.Set;
35 import org.apache.harmony.crypto.internal.NullCipherSpi;
36 import org.apache.harmony.security.fortress.Engine;
37 
38 /**
39  * This class provides access to implementations of cryptographic ciphers for
40  * encryption and decryption. Cipher classes can not be instantiated directly,
41  * one has to call the Cipher's {@code getInstance} method with the name of a
42  * requested transformation, optionally with a provider. A transformation
43  * specifies an operation (or a set of operations) as a string in the form:
44  * <ul>
45  * <li><i>"algorithm/mode/padding"</i></li> or
46  * <li><i>"algorithm"</i></li>
47  * </ul>
48  * <i>algorithm</i> is the name of a cryptographic algorithm, <i>mode</i> is the
49  * name of a feedback mode and <i>padding</i> is the name of a padding scheme.
50  * If <i>mode</i> and/or <i>padding</i> values are omitted, provider specific
51  * default values will be used.
52  * <p>
53  * A valid transformation would be:
54  * <ul>
55  * {@code Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");}
56  * </ul>
57  * When a block cipher is requested in in stream cipher mode, the number of bits
58  * to be processed at a time can be optionally specified by appending it to the
59  * mode name. e.g. <i>"AES/CFB8/NoPadding"</i>. If no number is specified, a
60  * provider specific default value is used.
61  */
62 public class Cipher {
63 
64     /**
65      * Constant for decryption operation mode.
66      */
67     public static final int DECRYPT_MODE = 2;
68 
69     /**
70      * Constant for encryption operation mode.
71      */
72     public static final int ENCRYPT_MODE = 1;
73 
74     /**
75      * Constant indicating that the key to be unwrapped is a private key.
76      */
77     public static final int PRIVATE_KEY = 2;
78 
79     /**
80      * Constant indicating that the key to be unwrapped is a public key.
81      */
82     public static final int PUBLIC_KEY = 1;
83 
84     /**
85      * Constant indicating that the key to be unwrapped is a secret key.
86      */
87     public static final int SECRET_KEY = 3;
88 
89     /**
90      * Constant for key unwrapping operation mode.
91      */
92     public static final int UNWRAP_MODE = 4;
93 
94     /**
95      * Constant for key wrapping operation mode.
96      */
97     public static final int WRAP_MODE = 3;
98 
99     private int mode;
100 
101     /**
102      * The service name.
103      */
104     private static final String SERVICE = "Cipher";
105 
106     /**
107      * Used to access common engine functionality.
108      */
109     private static final Engine ENGINE = new Engine(SERVICE);
110 
111     /**
112      * The provider.
113      */
114     private Provider provider;
115 
116     /**
117      * The SPI implementation.
118      */
119     private CipherSpi spiImpl;
120 
121     /**
122      * The transformation.
123      */
124     private String transformation;
125 
126     private static SecureRandom secureRandom;
127 
128     /**
129      * Creates a new Cipher instance.
130      *
131      * @param cipherSpi
132      *            the implementation delegate of the cipher.
133      * @param provider
134      *            the provider of the implementation of this cipher.
135      * @param transformation
136      *            the name of the transformation that this cipher performs.
137      * @throws NullPointerException
138      *             if either cipherSpi is {@code null} or provider is {@code
139      *             null} and {@code cipherSpi} is a {@code NullCipherSpi}.
140      */
Cipher(CipherSpi cipherSpi, Provider provider, String transformation)141     protected Cipher(CipherSpi cipherSpi, Provider provider,
142             String transformation) {
143         if (cipherSpi == null) {
144             throw new NullPointerException("cipherSpi == null");
145         }
146         if (!(cipherSpi instanceof NullCipherSpi) && provider == null) {
147             throw new NullPointerException("provider == null");
148         }
149         this.provider = provider;
150         this.transformation = transformation;
151         this.spiImpl = cipherSpi;
152     }
153 
154     /**
155      * Creates a new Cipher for the specified transformation. The installed
156      * providers are searched in order for an implementation of the specified
157      * transformation. The first found provider providing the transformation is
158      * used to create the cipher. If no provider is found an exception is
159      * thrown.
160      *
161      * @param transformation
162      *            the name of the transformation to create a cipher for.
163      * @return a cipher for the requested transformation.
164      * @throws NoSuchAlgorithmException
165      *             if no installed provider can provide the
166      *             <i>transformation</i>, or it is {@code null}, empty or in an
167      *             invalid format.
168      * @throws NoSuchPaddingException
169      *             if no installed provider can provide the padding scheme in
170      *             the <i>transformation</i>.
171      */
getInstance(String transformation)172     public static final Cipher getInstance(String transformation)
173             throws NoSuchAlgorithmException, NoSuchPaddingException {
174         return getCipher(transformation, null);
175     }
176 
177     /**
178      * Creates a new cipher for the specified transformation provided by the
179      * specified provider.
180      *
181      * @param transformation
182      *            the name of the transformation to create a cipher for.
183      * @param provider
184      *            the name of the provider to ask for the transformation.
185      * @return a cipher for the requested transformation.
186      * @throws NoSuchAlgorithmException
187      *             if the specified provider can not provide the
188      *             <i>transformation</i>, or it is {@code null}, empty or in an
189      *             invalid format.
190      * @throws NoSuchProviderException
191      *             if no provider with the specified name can be found.
192      * @throws NoSuchPaddingException
193      *             if the requested padding scheme in the <i>transformation</i>
194      *             is not available.
195      * @throws IllegalArgumentException
196      *             if the specified provider is {@code null}.
197      */
getInstance(String transformation, String provider)198     public static final Cipher getInstance(String transformation,
199             String provider) throws NoSuchAlgorithmException,
200             NoSuchProviderException, NoSuchPaddingException {
201 
202         if (provider == null) {
203             throw new IllegalArgumentException("provider == null");
204         }
205 
206         Provider p = Security.getProvider(provider);
207         if (p == null) {
208             throw new NoSuchProviderException("Provider not available: " + provider);
209         }
210         return getInstance(transformation, p);
211     }
212 
213     /**
214      * Creates a new cipher for the specified transformation.
215      *
216      * @param transformation
217      *            the name of the transformation to create a cipher for.
218      * @param provider
219      *            the provider to ask for the transformation.
220      * @return a cipher for the requested transformation.
221      * @throws NoSuchAlgorithmException
222      *             if the specified provider can not provide the
223      *             <i>transformation</i>, or it is {@code null}, empty or in an
224      *             invalid format.
225      * @throws NoSuchPaddingException
226      *             if the requested padding scheme in the <i>transformation</i>
227      *             is not available.
228      * @throws IllegalArgumentException
229      *             if the provider is {@code null}.
230      */
getInstance(String transformation, Provider provider)231     public static final Cipher getInstance(String transformation,
232             Provider provider) throws NoSuchAlgorithmException,
233             NoSuchPaddingException {
234         if (provider == null) {
235             throw new IllegalArgumentException("provider == null");
236         }
237         Cipher c = getCipher(transformation, provider);
238         return c;
239     }
240 
invalidTransformation(String transformation)241     private static NoSuchAlgorithmException invalidTransformation(String transformation)
242             throws NoSuchAlgorithmException {
243         throw new NoSuchAlgorithmException("Invalid transformation: " + transformation);
244     }
245 
246     /**
247      * Find appropriate Cipher according the specification rules
248      *
249      * @param transformation
250      * @param provider
251      * @return
252      * @throws NoSuchAlgorithmException
253      * @throws NoSuchPaddingException
254      */
getCipher(String transformation, Provider provider)255     private static synchronized Cipher getCipher(String transformation, Provider provider)
256             throws NoSuchAlgorithmException, NoSuchPaddingException {
257 
258         if (transformation == null || transformation.isEmpty()) {
259             throw invalidTransformation(transformation);
260         }
261 
262         String[] transf = checkTransformation(transformation);
263 
264         boolean needSetPadding = false;
265         boolean needSetMode = false;
266         Object engineSpi = null;
267         Provider engineProvider = provider;
268         if (transf[1] == null && transf[2] == null) { // "algorithm"
269             if (provider == null) {
270                 Engine.SpiAndProvider sap = ENGINE.getInstance(transf[0], null);
271                 engineSpi = sap.spi;
272                 engineProvider = sap.provider;
273             } else {
274                 engineSpi = ENGINE.getInstance(transf[0], provider, null);
275             }
276         } else {
277             String[] searchOrder = {
278                 transf[0] + "/" + transf[1] + "/" + transf[2], // "algorithm/mode/padding"
279                 transf[0] + "/" + transf[1], // "algorithm/mode"
280                 transf[0] + "//" + transf[2], // "algorithm//padding"
281                 transf[0] // "algorithm"
282             };
283             int i;
284             for (i = 0; i < searchOrder.length; i++) {
285                 try {
286                     if (provider == null) {
287                         Engine.SpiAndProvider sap = ENGINE.getInstance(searchOrder[i], null);
288                         engineSpi = sap.spi;
289                         engineProvider = sap.provider;
290                     } else {
291                         engineSpi = ENGINE.getInstance(searchOrder[i], provider, null);
292                     }
293                     break;
294                 } catch (NoSuchAlgorithmException e) {
295                     if (i == searchOrder.length-1) {
296                         throw new NoSuchAlgorithmException(transformation, e);
297                     }
298                 }
299             }
300             switch (i) {
301                 case 1: // "algorithm/mode"
302                     needSetPadding = true;
303                     break;
304                 case 2: // "algorithm//padding"
305                     needSetMode = true;
306                     break;
307                 case 3: // "algorithm"
308                     needSetPadding = true;
309                     needSetMode = true;
310             }
311         }
312         if (engineSpi == null || engineProvider == null) {
313             throw new NoSuchAlgorithmException(transformation);
314         }
315         if (!(engineSpi instanceof CipherSpi)) {
316             throw new NoSuchAlgorithmException(engineSpi.getClass().getName());
317         }
318         CipherSpi cspi = (CipherSpi) engineSpi;
319         Cipher c = new Cipher(cspi, engineProvider, transformation);
320         if (needSetMode) {
321             c.spiImpl.engineSetMode(transf[1]);
322         }
323         if (needSetPadding) {
324             c.spiImpl.engineSetPadding(transf[2]);
325         }
326         return c;
327     }
328 
checkTransformation(String transformation)329     private static String[] checkTransformation(String transformation) throws NoSuchAlgorithmException {
330         // ignore an extra prefix / characters such as in
331         // "/DES/CBC/PKCS5Paddin" http://b/3387688
332         if (transformation.startsWith("/")) {
333             transformation = transformation.substring(1);
334         }
335         // 'transformation' should be of the form "algorithm/mode/padding".
336         String[] pieces = transformation.split("/");
337         if (pieces.length > 3) {
338             throw invalidTransformation(transformation);
339         }
340         // Empty or missing pieces are represented by null.
341         String[] result = new String[3];
342         for (int i = 0; i < pieces.length; ++i) {
343             String piece = pieces[i].trim();
344             if (!piece.isEmpty()) {
345                 result[i] = piece;
346             }
347         }
348         // You MUST specify an algorithm.
349         if (result[0] == null) {
350             throw invalidTransformation(transformation);
351         }
352         if (!(result[1] == null && result[2] == null) && (result[1] == null || result[2] == null)) {
353             throw invalidTransformation(transformation);
354         }
355         return result;
356     }
357 
358     /**
359      * Returns the provider of this cipher instance.
360      *
361      * @return the provider of this cipher instance.
362      */
getProvider()363     public final Provider getProvider() {
364         return provider;
365     }
366 
367     /**
368      * Returns the name of the algorithm of this cipher instance.
369      * <p>
370      * This is the name of the <i>transformation</i> argument used in the
371      * {@code getInstance} call creating this object.
372      *
373      * @return the name of the algorithm of this cipher instance.
374      */
getAlgorithm()375     public final String getAlgorithm() {
376         return transformation;
377     }
378 
379     /**
380      * Returns this ciphers block size (in bytes).
381      *
382      * @return this ciphers block size.
383      */
getBlockSize()384     public final int getBlockSize() {
385         return spiImpl.engineGetBlockSize();
386     }
387 
388     /**
389      * Returns the length in bytes an output buffer needs to be when this cipher
390      * is updated with {@code inputLen} bytes.
391      *
392      * @param inputLen
393      *            the number of bytes of the input.
394      * @return the output buffer length for the input length.
395      * @throws IllegalStateException
396      *             if this cipher instance is in an invalid state.
397      */
getOutputSize(int inputLen)398     public final int getOutputSize(int inputLen) {
399         if (mode == 0) {
400             throw new IllegalStateException("Cipher has not yet been initialized");
401         }
402         return spiImpl.engineGetOutputSize(inputLen);
403     }
404 
405     /**
406      * Returns the <i>initialization vector</i> for this cipher instance.
407      *
408      * @return the <i>initialization vector</i> for this cipher instance.
409      */
getIV()410     public final byte[] getIV() {
411         return spiImpl.engineGetIV();
412     }
413 
414     /**
415      * Returns the parameters that where used to create this cipher instance.
416      * <p>
417      * These may be a the same parameters that were used to create this cipher
418      * instance, or may be a combination of default and random parameters,
419      * depending on the underlying cipher implementation.
420      *
421      * @return the parameters that where used to create this cipher instance, or
422      *         {@code null} if this cipher instance does not have any
423      *         parameters.
424      */
getParameters()425     public final AlgorithmParameters getParameters() {
426         return spiImpl.engineGetParameters();
427     }
428 
429     /**
430      * Returns the exemption mechanism associated with this cipher.
431      *
432      * @return currently {@code null}
433      */
getExemptionMechanism()434     public final ExemptionMechanism getExemptionMechanism() {
435         //FIXME implement getExemptionMechanism
436 
437         //        try {
438         //            return ExemptionMechanism.getInstance(transformation, provider);
439         //        } catch (NoSuchAlgorithmException e) {
440         return null;
441         //        }
442 
443     }
444 
445     /**
446      * Initializes this cipher instance with the specified key.
447      * <p>
448      * The cipher is initialized for the specified operational mode (one of:
449      * encryption, decryption, key wrapping or key unwrapping) depending on
450      * {@code opmode}.
451      * <p>
452      * If this cipher instance needs any algorithm parameters or random values
453      * that the specified key can not provide, the underlying implementation of
454      * this cipher is supposed to generate the required parameters (using its
455      * provider or random values).
456      * <p>
457      * When a cipher instance is initialized by a call to any of the {@code
458      * init} methods, the state of the instance is overridden, meaning that it
459      * is equivalent to creating a new instance and calling its {@code init}
460      * method.
461      *
462      * @param opmode
463      *            the operation this cipher instance should be initialized for
464      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
465      *            WRAP_MODE} or {@code UNWRAP_MODE}).
466      * @param key
467      *            the input key for the operation.
468      * @throws InvalidKeyException
469      *             if the specified key can not be used to initialize this
470      *             cipher instance.
471      */
init(int opmode, Key key)472     public final void init(int opmode, Key key) throws InvalidKeyException {
473         if (secureRandom == null) {
474             // In theory it might be thread-unsafe but in the given case it's OK
475             // since it does not matter which SecureRandom instance is passed
476             // to the init()
477             secureRandom = new SecureRandom();
478         }
479         init(opmode, key, secureRandom);
480     }
481 
482     /**
483      * Initializes this cipher instance with the specified key and a source of
484      * randomness.
485      * <p>
486      * The cipher is initialized for the specified operational mode (one of:
487      * encryption, decryption, key wrapping or key unwrapping) depending on
488      * {@code opmode}.
489      * <p>
490      * If this cipher instance needs any algorithm parameters or random values
491      * that the specified key can not provide, the underlying implementation of
492      * this cipher is supposed to generate the required parameters (using its
493      * provider or random values). Random values are generated using {@code
494      * random};
495      * <p>
496      * When a cipher instance is initialized by a call to any of the {@code
497      * init} methods, the state of the instance is overridden, means it is
498      * equivalent to creating a new instance and calling it {@code init} method.
499      *
500      * @param opmode
501      *            the operation this cipher instance should be initialized for
502      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
503      *            WRAP_MODE} or {@code UNWRAP_MODE}).
504      * @param key
505      *            the input key for the operation.
506      * @param random
507      *            the source of randomness to use.
508      * @throws InvalidKeyException
509      *             if the specified key can not be used to initialize this
510      *             cipher instance.
511      * @throws InvalidParameterException
512      *             if the specified opmode is invalid.
513      */
init(int opmode, Key key, SecureRandom random)514     public final void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException {
515         checkMode(opmode);
516         //        FIXME InvalidKeyException
517         //        if keysize exceeds the maximum allowable keysize
518         //        (jurisdiction policy files)
519         spiImpl.engineInit(opmode, key, random);
520         mode = opmode;
521     }
522 
checkMode(int mode)523     private void checkMode(int mode) {
524         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE
525             && mode != UNWRAP_MODE && mode != WRAP_MODE) {
526             throw new InvalidParameterException("Invalid mode: " + mode);
527         }
528     }
529 
530     /**
531      * Initializes this cipher instance with the specified key and algorithm
532      * parameters.
533      * <p>
534      * The cipher is initialized for the specified operational mode (one of:
535      * encryption, decryption, key wrapping or key unwrapping).
536      * <p>
537      * If this cipher instance needs any algorithm parameters and {@code params}
538      * is {@code null}, the underlying implementation of this cipher is supposed
539      * to generate the required parameters (using its provider or random
540      * values).
541      * <p>
542      * When a cipher instance is initialized by a call to any of the {@code
543      * init} methods, the state of the instance is overridden, means it is
544      * equivalent to creating a new instance and calling it {@code init} method.
545      *
546      * @param opmode
547      *            the operation this cipher instance should be initialized for
548      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
549      *            WRAP_MODE} or {@code UNWRAP_MODE}).
550      * @param key
551      *            the input key for the operation.
552      * @param params
553      *            the algorithm parameters.
554      * @throws InvalidKeyException
555      *             if the specified key can not be used to initialize this
556      *             cipher instance.
557      * @throws InvalidAlgorithmParameterException
558      *             it the specified parameters are inappropriate for this
559      *             cipher.
560      */
init(int opmode, Key key, AlgorithmParameterSpec params)561     public final void init(int opmode, Key key, AlgorithmParameterSpec params)
562             throws InvalidKeyException, InvalidAlgorithmParameterException {
563         if (secureRandom == null) {
564             secureRandom = new SecureRandom();
565         }
566         init(opmode, key, params, secureRandom);
567     }
568 
569     /**
570      * Initializes this cipher instance with the specified key, algorithm
571      * parameters and a source of randomness.
572      * <p>
573      * The cipher is initialized for the specified operational mode (one of:
574      * encryption, decryption, key wrapping or key unwrapping) depending on
575      * {@code opmode}.
576      * <p>
577      * If this cipher instance needs any algorithm parameters and {@code params}
578      * is {@code null}, the underlying implementation of this cipher is supposed
579      * to generate the required parameters (using its provider or random
580      * values). Random values are generated using {@code random};
581      * <p>
582      * When a cipher instance is initialized by a call to any of the {@code
583      * init} methods, the state of the instance is overridden, meaning that it
584      * is equivalent to creating a new instance and calling it {@code init}
585      * method.
586      *
587      * @param opmode
588      *            the operation this cipher instance should be initialized for
589      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
590      *            WRAP_MODE} or {@code UNWRAP_MODE}).
591      * @param key
592      *            the input key for the operation.
593      * @param params
594      *            the algorithm parameters.
595      * @param random
596      *            the source of randomness to use.
597      * @throws InvalidKeyException
598      *             if the specified key can not be used to initialize this
599      *             cipher instance.
600      * @throws InvalidAlgorithmParameterException
601      *             it the specified parameters are inappropriate for this
602      *             cipher.
603      * @throws InvalidParameterException
604      *             if the specified {@code opmode} is invalid.
605      */
init(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random)606     public final void init(int opmode, Key key, AlgorithmParameterSpec params,
607             SecureRandom random) throws InvalidKeyException,
608             InvalidAlgorithmParameterException {
609         checkMode(opmode);
610         //        FIXME InvalidKeyException
611         //        if keysize exceeds the maximum allowable keysize
612         //        (jurisdiction policy files)
613         //        FIXME InvalidAlgorithmParameterException
614         //        cryptographic strength exceed the legal limits
615         //        (jurisdiction policy files)
616         spiImpl.engineInit(opmode, key, params, random);
617         mode = opmode;
618     }
619 
620     /**
621      * Initializes this cipher instance with the specified key and algorithm
622      * parameters.
623      * <p>
624      * The cipher is initialized for the specified operation (one of:
625      * encryption, decryption, key wrapping or key unwrapping) depending on
626      * {@code opmode}.
627      * <p>
628      * If this cipher instance needs any algorithm parameters and {@code params}
629      * is {@code null}, the underlying implementation of this cipher is supposed
630      * to generate the required parameters (using its provider or random
631      * values).
632      * <p>
633      * When a cipher instance is initialized by a call to any of the {@code
634      * init} methods, the state of the instance is overridden, meaning that it
635      * is equivalent to creating a new instance and calling it {@code init}
636      * method.
637      *
638      * @param opmode
639      *            the operation this cipher instance should be initialized for
640      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
641      *            WRAP_MODE} or {@code UNWRAP_MODE}).
642      * @param key
643      *            the input key for the operation.
644      * @param params
645      *            the algorithm parameters.
646      * @throws InvalidKeyException
647      *             if the specified key can not be used to initialize this
648      *             cipher instance.
649      * @throws InvalidAlgorithmParameterException
650      *             it the specified parameters are inappropriate for this
651      *             cipher.
652      */
init(int opmode, Key key, AlgorithmParameters params)653     public final void init(int opmode, Key key, AlgorithmParameters params)
654             throws InvalidKeyException, InvalidAlgorithmParameterException {
655         if (secureRandom == null) {
656             secureRandom = new SecureRandom();
657         }
658         init(opmode, key, params, secureRandom);
659     }
660 
661     /**
662      * Initializes this cipher instance with the specified key, algorithm
663      * parameters and a source of randomness.
664      * <p>
665      * The cipher will be initialized for the specified operation (one of:
666      * encryption, decryption, key wrapping or key unwrapping) depending on
667      * {@code opmode}.
668      * <p>
669      * If this cipher instance needs any algorithm parameters and {@code params}
670      * is {@code null}, the underlying implementation of this cipher is supposed
671      * to generate the required parameters (using its provider or random
672      * values). Random values are generated using {@code random}.
673      * <p>
674      * When a cipher instance is initialized by a call to any of the {@code
675      * init} methods, the state of the instance is overridden, means it is
676      * equivalent to creating a new instance and calling it {@code init} method.
677      *
678      * @param opmode
679      *            the operation this cipher instance should be initialized for
680      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
681      *            WRAP_MODE} or {@code UNWRAP_MODE}).
682      * @param key
683      *            the input key for the operation.
684      * @param params
685      *            the algorithm parameters.
686      * @param random
687      *            the source of randomness to use.
688      * @throws InvalidKeyException
689      *             if the specified key can not be used to initialize this
690      *             cipher instance.
691      * @throws InvalidAlgorithmParameterException
692      *             if the specified parameters are inappropriate for this
693      *             cipher.
694      * @throws InvalidParameterException
695      *             if the specified {@code opmode} is invalid.
696      */
init(int opmode, Key key, AlgorithmParameters params, SecureRandom random)697     public final void init(int opmode, Key key, AlgorithmParameters params,
698             SecureRandom random) throws InvalidKeyException,
699             InvalidAlgorithmParameterException {
700         checkMode(opmode);
701         //        FIXME InvalidKeyException
702         //        if keysize exceeds the maximum allowable keysize
703         //        (jurisdiction policy files)
704         //        FIXME InvalidAlgorithmParameterException
705         //        cryptographic strength exceed the legal limits
706         //        (jurisdiction policy files)
707         spiImpl.engineInit(opmode, key, params, random);
708         mode = opmode;
709     }
710 
711     /**
712      * Initializes this cipher instance with the public key from the specified
713      * certificate.
714      * <p>
715      * The cipher will be initialized for the specified operation (one of:
716      * encryption, decryption, key wrapping or key unwrapping) depending on
717      * {@code opmode}.
718      * <p>
719      * It the type of the certificate is X.509 and the certificate has a <i>key
720      * usage</i> extension field marked as critical, the specified {@code
721      * opmode} has the be enabled for this key, otherwise an {@code
722      * InvalidKeyException} is thrown.
723      * <p>
724      * If this cipher instance needs any algorithm parameters that the key in
725      * the certificate can not provide, the underlying implementation of this
726      * cipher is supposed to generate the required parameters (using its
727      * provider or random values).
728      * <p>
729      * When a cipher instance is initialized by a call to any of the {@code
730      * init} methods, the state of the instance is overridden, means it is
731      * equivalent to creating a new instance and calling it {@code init} method.
732      *
733      * @param opmode
734      *            the operation this cipher instance should be initialized for
735      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
736      *            WRAP_MODE} or {@code UNWRAP_MODE}).
737      * @param certificate
738      *            the certificate.
739      * @throws InvalidKeyException
740      *             if the public key in the certificate can not be used to
741      *             initialize this cipher instance.
742      */
init(int opmode, Certificate certificate)743     public final void init(int opmode, Certificate certificate)
744             throws InvalidKeyException {
745         if (secureRandom == null) {
746             secureRandom = new SecureRandom();
747         }
748         init(opmode, certificate, secureRandom);
749     }
750 
751     /**
752      * Initializes this cipher instance with the public key from the specified
753      * certificate and a source of randomness.
754      * <p>
755      * The cipher will be initialized for the specified operation (one of:
756      * encryption, decryption, key wrapping or key unwrapping) depending on
757      * {@code opmode}.
758      * <p>
759      * It the type of the certificate is X.509 and the certificate has a <i>key
760      * usage</i> extension field marked as critical, the specified {@code
761      * opmode} has the be enabled for this key, otherwise an {@code
762      * InvalidKeyException} is thrown.
763      * <p>
764      * If this cipher instance needs any algorithm parameters that the key in
765      * the certificate can not provide, the underlying implementation of this
766      * cipher is supposed to generate the required parameters (using its
767      * provider or random values). Random values are generated using {@code
768      * random}.
769      * <p>
770      * When a cipher instance is initialized by a call to any of the {@code
771      * init} methods, the state of the instance is overridden, means it is
772      * equivalent to creating a new instance and calling it {@code init} method.
773      *
774      * @param opmode
775      *            the operation this cipher instance should be initialized for
776      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
777      *            WRAP_MODE} or {@code UNWRAP_MODE}).
778      * @param certificate
779      *            the certificate.
780      * @param random
781      *            the source of randomness to be used.
782      * @throws InvalidKeyException
783      *             if the public key in the certificate can not be used to
784      *             initialize this cipher instance.
785      */
init(int opmode, Certificate certificate, SecureRandom random)786     public final void init(int opmode, Certificate certificate,
787             SecureRandom random) throws InvalidKeyException {
788         checkMode(opmode);
789         if (certificate instanceof X509Certificate) {
790             Set<String> ce = ((X509Certificate) certificate).getCriticalExtensionOIDs();
791             boolean critical = false;
792             if (ce != null && !ce.isEmpty()) {
793                 for (String oid : ce) {
794                     if (oid.equals("2.5.29.15")) { // KeyUsage OID = 2.5.29.15
795                         critical = true;
796                         break;
797                     }
798                 }
799                 if (critical) {
800                     boolean[] keyUsage = ((X509Certificate) certificate).getKeyUsage();
801                     // As specified in RFC 3280:
802                     //   Internet X.509 Public Key Infrastructure
803                     //   Certificate and Certificate Revocation List (CRL) Profile.
804                     // Section 4.2.1.3  Key Usage
805                     // http://www.ietf.org/rfc/rfc3280.txt
806                     //
807                     // KeyUsage ::= BIT STRING {digitalSignature (0),
808                     //                          nonRepudiation   (1),
809                     //                          keyEncipherment  (2),
810                     //                          dataEncipherment (3),
811                     //                          keyAgreement     (4),
812                     //                          keyCertSign      (5),
813                     //                          cRLSign          (6),
814                     //                          encipherOnly     (7),
815                     //                          decipherOnly     (8) }
816                     if (keyUsage != null) {
817                         if (opmode == ENCRYPT_MODE && !keyUsage[3]) {
818                             throw new InvalidKeyException("The public key in the certificate "
819                                                           + "cannot be used for ENCRYPT_MODE");
820                         } else if (opmode == WRAP_MODE && !keyUsage[2]) {
821                             throw new InvalidKeyException("The public key in the certificate "
822                                                           + "cannot be used for WRAP_MODE");
823                         }
824                     }
825                 }
826             }
827         }
828         //        FIXME InvalidKeyException
829         //        if keysize exceeds the maximum allowable keysize
830         //        (jurisdiction policy files)
831         spiImpl.engineInit(opmode, certificate.getPublicKey(), random);
832         mode = opmode;
833     }
834 
835     /**
836      * Continues a multi-part transformation (encryption or decryption). The
837      * transformed bytes are returned.
838      *
839      * @param input
840      *            the input bytes to transform.
841      * @return the transformed bytes in a new buffer, or {@code null} if the
842      *         input has zero length.
843      * @throws IllegalStateException
844      *             if this cipher instance is not initialized for encryption or
845      *             decryption.
846      * @throws IllegalArgumentException
847      *             if the input is {@code null}.
848      */
update(byte[] input)849     public final byte[] update(byte[] input) {
850         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
851             throw new IllegalStateException();
852         }
853         if (input == null) {
854             throw new IllegalArgumentException("input == null");
855         }
856         if (input.length == 0) {
857             return null;
858         }
859         return spiImpl.engineUpdate(input, 0, input.length);
860     }
861 
862     /**
863      * Continues a multi-part transformation (encryption or decryption). The
864      * transformed bytes are returned.
865      *
866      * @param input
867      *            the input bytes to transform.
868      * @param inputOffset
869      *            the offset in the input to start.
870      * @param inputLen
871      *            the length of the input to transform.
872      * @return the transformed bytes in a new buffer, or {@code null} if the
873      *         input has zero length.
874      * @throws IllegalStateException
875      *             if this cipher instance is not initialized for encryption or
876      *             decryption.
877      * @throws IllegalArgumentException
878      *             if the input is {@code null}, or if {@code inputOffset} and
879      *             {@code inputLen} do not specify a valid chunk in the input
880      *             buffer.
881      */
update(byte[] input, int inputOffset, int inputLen)882     public final byte[] update(byte[] input, int inputOffset, int inputLen) {
883         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
884             throw new IllegalStateException();
885         }
886         if (input == null) {
887             throw new IllegalArgumentException("input == null");
888         }
889         checkInputOffsetAndCount(input.length, inputOffset, inputLen);
890         if (input.length == 0) {
891             return null;
892         }
893         return spiImpl.engineUpdate(input, inputOffset, inputLen);
894     }
895 
checkInputOffsetAndCount(int inputArrayLength, int inputOffset, int inputLen)896     private static void checkInputOffsetAndCount(int inputArrayLength,
897                                                  int inputOffset,
898                                                  int inputLen) {
899         if ((inputOffset | inputLen) < 0
900                 || inputOffset > inputArrayLength
901                 || inputArrayLength - inputOffset < inputLen) {
902             throw new IllegalArgumentException("input.length=" + inputArrayLength
903                                                + "; inputOffset=" + inputOffset
904                                                + "; inputLen=" + inputLen);
905         }
906     }
907 
908     /**
909      * Continues a multi-part transformation (encryption or decryption). The
910      * transformed bytes are stored in the {@code output} buffer.
911      * <p>
912      * If the size of the {@code output} buffer is too small to hold the result,
913      * a {@code ShortBufferException} is thrown. Use
914      * {@link Cipher#getOutputSize getOutputSize} to check for the size of the
915      * output buffer.
916      *
917      * @param input
918      *            the input bytes to transform.
919      * @param inputOffset
920      *            the offset in the input to start.
921      * @param inputLen
922      *            the length of the input to transform.
923      * @param output
924      *            the output buffer.
925      * @return the number of bytes placed in output.
926      * @throws ShortBufferException
927      *             if the size of the {@code output} buffer is too small.
928      * @throws IllegalStateException
929      *             if this cipher instance is not initialized for encryption or
930      *             decryption.
931      * @throws IllegalArgumentException
932      *             if the input is {@code null}, the output is {@code null}, or
933      *             if {@code inputOffset} and {@code inputLen} do not specify a
934      *             valid chunk in the input buffer.
935      */
update(byte[] input, int inputOffset, int inputLen, byte[] output)936     public final int update(byte[] input, int inputOffset, int inputLen,
937             byte[] output) throws ShortBufferException {
938         return update(input, inputOffset, inputLen, output, 0);
939     }
940 
941     /**
942      * Continues a multi-part transformation (encryption or decryption). The
943      * transformed bytes are stored in the {@code output} buffer.
944      * <p>
945      * If the size of the {@code output} buffer is too small to hold the result,
946      * a {@code ShortBufferException} is thrown. Use
947      * {@link Cipher#getOutputSize getOutputSize} to check for the size of the
948      * output buffer.
949      *
950      * @param input
951      *            the input bytes to transform.
952      * @param inputOffset
953      *            the offset in the input to start.
954      * @param inputLen
955      *            the length of the input to transform.
956      * @param output
957      *            the output buffer.
958      * @param outputOffset
959      *            the offset in the output buffer.
960      * @return the number of bytes placed in output.
961      * @throws ShortBufferException
962      *             if the size of the {@code output} buffer is too small.
963      * @throws IllegalStateException
964      *             if this cipher instance is not initialized for encryption or
965      *             decryption.
966      * @throws IllegalArgumentException
967      *             if the input is {@code null}, the output is {@code null}, or
968      *             if {@code inputOffset} and {@code inputLen} do not specify a
969      *             valid chunk in the input buffer.
970      */
update(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)971     public final int update(byte[] input, int inputOffset, int inputLen,
972             byte[] output, int outputOffset) throws ShortBufferException {
973         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
974             throw new IllegalStateException();
975         }
976         if (input == null) {
977             throw new IllegalArgumentException("input == null");
978         }
979         if (output == null) {
980             throw new IllegalArgumentException("output == null");
981         }
982         if (outputOffset < 0) {
983             throw new IllegalArgumentException("outputOffset < 0. outputOffset=" + outputOffset);
984         }
985         checkInputOffsetAndCount(input.length, inputOffset, inputLen);
986         if (input.length == 0) {
987             return 0;
988         }
989         return spiImpl.engineUpdate(input, inputOffset, inputLen, output,
990                 outputOffset);
991     }
992 
993     /**
994      * Continues a multi-part transformation (encryption or decryption). The
995      * {@code input.remaining()} bytes starting at {@code input.position()} are
996      * transformed and stored in the {@code output} buffer.
997      * <p>
998      * If the {@code output.remaining()} is too small to hold the transformed
999      * bytes a {@code ShortBufferException} is thrown. Use
1000      * {@link Cipher#getOutputSize getOutputSize} to check for the size of the
1001      * output buffer.
1002      *
1003      * @param input
1004      *            the input buffer to transform.
1005      * @param output
1006      *            the output buffer to store the result within.
1007      * @return the number of bytes stored in the output buffer.
1008      * @throws ShortBufferException
1009      *             if the size of the {@code output} buffer is too small.
1010      * @throws IllegalStateException
1011      *             if this cipher instance is not initialized for encryption or
1012      *             decryption.
1013      * @throws IllegalArgumentException
1014      *             if the input buffer and the output buffer are the identical
1015      *             object.
1016      */
update(ByteBuffer input, ByteBuffer output)1017     public final int update(ByteBuffer input, ByteBuffer output)
1018             throws ShortBufferException {
1019         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1020             throw new IllegalStateException();
1021         }
1022         if (input == output) {
1023             throw new IllegalArgumentException("input == output");
1024         }
1025         return spiImpl.engineUpdate(input, output);
1026     }
1027 
1028     /**
1029      * Finishes a multi-part transformation (encryption or decryption).
1030      * <p>
1031      * Processes any bytes that may have been buffered in previous {@code
1032      * update} calls.
1033      *
1034      * @return the final bytes from the transformation.
1035      * @throws IllegalBlockSizeException
1036      *             if the size of the resulting bytes is not a multiple of the
1037      *             cipher block size.
1038      * @throws BadPaddingException
1039      *             if the padding of the data does not match the padding scheme.
1040      * @throws IllegalStateException
1041      *             if this cipher instance is not initialized for encryption or
1042      *             decryption.
1043      */
doFinal()1044     public final byte[] doFinal() throws IllegalBlockSizeException,
1045             BadPaddingException {
1046         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1047             throw new IllegalStateException();
1048         }
1049         return spiImpl.engineDoFinal(null, 0, 0);
1050     }
1051 
1052     /**
1053      * Finishes a multi-part transformation (encryption or decryption).
1054      * <p>
1055      * Processes any bytes that may have been buffered in previous {@code
1056      * update} calls.
1057      * <p>
1058      * The final transformed bytes are stored in the {@code output} buffer.
1059      *
1060      * @param output
1061      *            the output buffer.
1062      * @param outputOffset
1063      *            the offset in the output buffer.
1064      * @return the number of bytes placed in the output buffer.
1065      * @throws IllegalBlockSizeException
1066      *             if the size of the resulting bytes is not a multiple of the
1067      *             cipher block size.
1068      * @throws ShortBufferException
1069      *             if the size of the {@code output} buffer is too small.
1070      * @throws BadPaddingException
1071      *             if the padding of the data does not match the padding scheme.
1072      * @throws IllegalStateException
1073      *             if this cipher instance is not initialized for encryption or
1074      *             decryption.
1075      */
doFinal(byte[] output, int outputOffset)1076     public final int doFinal(byte[] output, int outputOffset)
1077             throws IllegalBlockSizeException, ShortBufferException,
1078             BadPaddingException {
1079         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1080             throw new IllegalStateException();
1081         }
1082         if (outputOffset < 0) {
1083             throw new IllegalArgumentException("outputOffset < 0. outputOffset=" + outputOffset);
1084         }
1085         return spiImpl.engineDoFinal(null, 0, 0, output, outputOffset);
1086     }
1087 
1088     /**
1089      * Finishes a multi-part transformation (encryption or decryption).
1090      * <p>
1091      * Processes the bytes in {@code input} buffer, and any bytes that have been
1092      * buffered in previous {@code update} calls.
1093      *
1094      * @param input
1095      *            the input buffer.
1096      * @return the final bytes from the transformation.
1097      * @throws IllegalBlockSizeException
1098      *             if the size of the resulting bytes is not a multiple of the
1099      *             cipher block size.
1100      * @throws BadPaddingException
1101      *             if the padding of the data does not match the padding scheme.
1102      * @throws IllegalStateException
1103      *             if this cipher instance is not initialized for encryption or
1104      *             decryption.
1105      */
doFinal(byte[] input)1106     public final byte[] doFinal(byte[] input) throws IllegalBlockSizeException,
1107             BadPaddingException {
1108         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1109             throw new IllegalStateException();
1110         }
1111         return spiImpl.engineDoFinal(input, 0, input.length);
1112     }
1113 
1114     /**
1115      * Finishes a multi-part transformation (encryption or decryption).
1116      * <p>
1117      * Processes the {@code inputLen} bytes in {@code input} buffer at {@code
1118      * inputOffset}, and any bytes that have been buffered in previous {@code
1119      * update} calls.
1120      *
1121      * @param input
1122      *            the input buffer.
1123      * @param inputOffset
1124      *            the offset in the input buffer.
1125      * @param inputLen
1126      *            the length of the input
1127      * @return the final bytes from the transformation.
1128      * @throws IllegalBlockSizeException
1129      *             if the size of the resulting bytes is not a multiple of the
1130      *             cipher block size.
1131      * @throws BadPaddingException
1132      *             if the padding of the data does not match the padding scheme.
1133      * @throws IllegalStateException
1134      *             if this cipher instance is not initialized for encryption or
1135      *             decryption.
1136      * @throws IllegalArgumentException
1137      *             if {@code inputOffset} and {@code inputLen} do not specify an
1138      *             valid chunk in the input buffer.
1139      */
doFinal(byte[] input, int inputOffset, int inputLen)1140     public final byte[] doFinal(byte[] input, int inputOffset, int inputLen)
1141             throws IllegalBlockSizeException, BadPaddingException {
1142         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1143             throw new IllegalStateException();
1144         }
1145         checkInputOffsetAndCount(input.length, inputOffset, inputLen);
1146         return spiImpl.engineDoFinal(input, inputOffset, inputLen);
1147     }
1148 
1149     /**
1150      * Finishes a multi-part transformation (encryption or decryption).
1151      * <p>
1152      * Processes the {@code inputLen} bytes in {@code input} buffer at {@code
1153      * inputOffset}, and any bytes that have been buffered in previous {@code
1154      * update} calls.
1155      *
1156      * @param input
1157      *            the input buffer.
1158      * @param inputOffset
1159      *            the offset in the input buffer.
1160      * @param inputLen
1161      *            the length of the input.
1162      * @param output
1163      *            the output buffer for the transformed bytes.
1164      * @return the number of bytes placed in the output buffer.
1165      * @throws ShortBufferException
1166      *             if the size of the {@code output} buffer is too small.
1167      * @throws IllegalBlockSizeException
1168      *             if the size of the resulting bytes is not a multiple of the
1169      *             cipher block size.
1170      * @throws BadPaddingException
1171      *             if the padding of the data does not match the padding scheme.
1172      * @throws IllegalStateException
1173      *             if this cipher instance is not initialized for encryption or
1174      *             decryption.
1175      * @throws IllegalArgumentException
1176      *             if {@code inputOffset} and {@code inputLen} do not specify an
1177      *             valid chunk in the input buffer.
1178      */
doFinal(byte[] input, int inputOffset, int inputLen, byte[] output)1179     public final int doFinal(byte[] input, int inputOffset, int inputLen,
1180             byte[] output) throws ShortBufferException,
1181             IllegalBlockSizeException, BadPaddingException {
1182         return doFinal(input, inputOffset, inputLen, output, 0);
1183     }
1184 
1185     /**
1186      * Finishes a multi-part transformation (encryption or decryption).
1187      * <p>
1188      * Processes the {@code inputLen} bytes in {@code input} buffer at {@code
1189      * inputOffset}, and any bytes that have been buffered in previous {@code
1190      * update} calls.
1191      *
1192      * @param input
1193      *            the input buffer.
1194      * @param inputOffset
1195      *            the offset in the input buffer.
1196      * @param inputLen
1197      *            the length of the input.
1198      * @param output
1199      *            the output buffer for the transformed bytes.
1200      * @param outputOffset
1201      *            the offset in the output buffer.
1202      * @return the number of bytes placed in the output buffer.
1203      * @throws ShortBufferException
1204      *             if the size of the {@code output} buffer is too small.
1205      * @throws IllegalBlockSizeException
1206      *             if the size of the resulting bytes is not a multiple of the
1207      *             cipher block size.
1208      * @throws BadPaddingException
1209      *             if the padding of the data does not match the padding scheme.
1210      * @throws IllegalStateException
1211      *             if this cipher instance is not initialized for encryption or
1212      *             decryption.
1213      * @throws IllegalArgumentException
1214      *             if {@code inputOffset} and {@code inputLen} do not specify an
1215      *             valid chunk in the input buffer.
1216      */
doFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)1217     public final int doFinal(byte[] input, int inputOffset, int inputLen,
1218             byte[] output, int outputOffset) throws ShortBufferException,
1219             IllegalBlockSizeException, BadPaddingException {
1220         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1221             throw new IllegalStateException();
1222         }
1223         checkInputOffsetAndCount(input.length, inputOffset, inputLen);
1224         return spiImpl.engineDoFinal(input, inputOffset, inputLen, output,
1225                 outputOffset);
1226     }
1227 
1228     /**
1229      * Finishes a multi-part transformation (encryption or decryption).
1230      * <p>
1231      * Processes the {@code input.remaining()} bytes in {@code input} buffer at
1232      * {@code input.position()}, and any bytes that have been buffered in
1233      * previous {@code update} calls. The transformed bytes are placed into
1234      * {@code output} buffer.
1235      *
1236      * @param input
1237      *            the input buffer.
1238      * @param output
1239      *            the output buffer.
1240      * @return the number of bytes placed into the output buffer.
1241      * @throws ShortBufferException
1242      *             if the size of the {@code output} buffer is too small.
1243      * @throws IllegalBlockSizeException
1244      *             if the size of the resulting bytes is not a multiple of the
1245      *             cipher block size.
1246      * @throws BadPaddingException
1247      *             if the padding of the data does not match the padding scheme.
1248      * @throws IllegalArgumentException
1249      *             if the input buffer and the output buffer are the same
1250      *             object.
1251      * @throws IllegalStateException
1252      *             if this cipher instance is not initialized for encryption or
1253      *             decryption.
1254      */
doFinal(ByteBuffer input, ByteBuffer output)1255     public final int doFinal(ByteBuffer input, ByteBuffer output)
1256             throws ShortBufferException, IllegalBlockSizeException,
1257             BadPaddingException {
1258         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1259             throw new IllegalStateException();
1260         }
1261         if (input == output) {
1262             throw new IllegalArgumentException("input == output");
1263         }
1264         return spiImpl.engineDoFinal(input, output);
1265     }
1266 
1267     /**
1268      * Wraps a key using this cipher instance.
1269      *
1270      * @param key
1271      *            the key to wrap.
1272      * @return the wrapped key.
1273      * @throws IllegalBlockSizeException
1274      *             if the size of the resulting bytes is not a multiple of the
1275      *             cipher block size.
1276      * @throws InvalidKeyException
1277      *             if this cipher instance can not wrap this key.
1278      * @throws IllegalStateException
1279      *             if this cipher instance is not initialized for wrapping.
1280      */
wrap(Key key)1281     public final byte[] wrap(Key key) throws IllegalBlockSizeException,
1282             InvalidKeyException {
1283         if (mode != WRAP_MODE) {
1284             throw new IllegalStateException();
1285         }
1286         return spiImpl.engineWrap(key);
1287     }
1288 
1289     /**
1290      * Unwraps a key using this cipher instance.
1291      *
1292      * @param wrappedKey
1293      *            the wrapped key to unwrap.
1294      * @param wrappedKeyAlgorithm
1295      *            the algorithm for the wrapped key.
1296      * @param wrappedKeyType
1297      *            the type of the wrapped key (one of: {@code SECRET_KEY
1298      *            <code>, <code>PRIVATE_KEY} or {@code PUBLIC_KEY})
1299      * @return the unwrapped key
1300      * @throws InvalidKeyException
1301      *             if the {@code wrappedKey} can not be unwrapped to a key of
1302      *             type {@code wrappedKeyType} for the {@code
1303      *             wrappedKeyAlgorithm}.
1304      * @throws NoSuchAlgorithmException
1305      *             if no provider can be found that can create a key of type
1306      *             {@code wrappedKeyType} for the {@code wrappedKeyAlgorithm}.
1307      * @throws IllegalStateException
1308      *             if this cipher instance is not initialized for unwrapping.
1309      */
unwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType)1310     public final Key unwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
1311             int wrappedKeyType) throws InvalidKeyException,
1312             NoSuchAlgorithmException {
1313         if (mode != UNWRAP_MODE) {
1314             throw new IllegalStateException();
1315         }
1316         return spiImpl.engineUnwrap(wrappedKey, wrappedKeyAlgorithm,
1317                 wrappedKeyType);
1318     }
1319 
1320     /**
1321      * Returns the maximum key length for the specified transformation.
1322      *
1323      * @param transformation
1324      *            the transformation name.
1325      * @return the maximum key length, currently {@code Integer.MAX_VALUE}.
1326      * @throws NoSuchAlgorithmException
1327      *             if no provider for the specified {@code transformation} can
1328      *             be found.
1329      * @throws NullPointerException
1330      *             if {@code transformation} is {@code null}.
1331      */
getMaxAllowedKeyLength(String transformation)1332     public static final int getMaxAllowedKeyLength(String transformation)
1333             throws NoSuchAlgorithmException {
1334         if (transformation == null) {
1335             throw new NullPointerException("transformation == null");
1336         }
1337         checkTransformation(transformation);
1338         //FIXME jurisdiction policy files
1339         return Integer.MAX_VALUE;
1340     }
1341 
1342     /**
1343      * Returns the maximum cipher parameter value for the specified
1344      * transformation. If there is no maximum limit, {@code null} is returned.
1345      *
1346      * @param transformation
1347      *            the transformation name.
1348      * @return a parameter spec holding the maximum value or {@code null}.
1349      *         Currently {@code null}.
1350      * @throws NoSuchAlgorithmException
1351      *             if no provider for the specified {@code transformation} can
1352      *             be found.
1353      * @throws NullPointerException
1354      *             if {@code transformation} is {@code null}.
1355      */
getMaxAllowedParameterSpec( String transformation)1356     public static final AlgorithmParameterSpec getMaxAllowedParameterSpec(
1357             String transformation) throws NoSuchAlgorithmException {
1358         if (transformation == null) {
1359             throw new NullPointerException("transformation == null");
1360         }
1361         checkTransformation(transformation);
1362         //FIXME jurisdiction policy files
1363         return null;
1364     }
1365 }
1366