• 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();
145         }
146         if (!(cipherSpi instanceof NullCipherSpi) && provider == null) {
147             throw new NullPointerException();
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         if (inputOffset < 0 || inputLen < 0
890                 || inputLen > input.length
891                 || inputOffset > input.length - inputLen) {
892             throw new IllegalArgumentException("Incorrect inputOffset/inputLen parameters");
893         }
894         if (input.length == 0) {
895             return null;
896         }
897         return spiImpl.engineUpdate(input, inputOffset, inputLen);
898     }
899 
900     /**
901      * Continues a multi-part transformation (encryption or decryption). The
902      * transformed bytes are stored in the {@code output} buffer.
903      * <p>
904      * If the size of the {@code output} buffer is too small to hold the result,
905      * a {@code ShortBufferException} is thrown. Use
906      * {@link Cipher#getOutputSize getOutputSize} to check for the size of the
907      * output buffer.
908      *
909      * @param input
910      *            the input bytes to transform.
911      * @param inputOffset
912      *            the offset in the input to start.
913      * @param inputLen
914      *            the length of the input to transform.
915      * @param output
916      *            the output buffer.
917      * @return the number of bytes placed in output.
918      * @throws ShortBufferException
919      *             if the size of the {@code output} buffer is too small.
920      * @throws IllegalStateException
921      *             if this cipher instance is not initialized for encryption or
922      *             decryption.
923      * @throws IllegalArgumentException
924      *             if the input is {@code null}, the output is {@code null}, or
925      *             if {@code inputOffset} and {@code inputLen} do not specify a
926      *             valid chunk in the input buffer.
927      */
update(byte[] input, int inputOffset, int inputLen, byte[] output)928     public final int update(byte[] input, int inputOffset, int inputLen,
929             byte[] output) throws ShortBufferException {
930         return update(input, inputOffset, inputLen, output, 0);
931     }
932 
933     /**
934      * Continues a multi-part transformation (encryption or decryption). The
935      * transformed bytes are stored in the {@code output} buffer.
936      * <p>
937      * If the size of the {@code output} buffer is too small to hold the result,
938      * a {@code ShortBufferException} is thrown. Use
939      * {@link Cipher#getOutputSize getOutputSize} to check for the size of the
940      * output buffer.
941      *
942      * @param input
943      *            the input bytes to transform.
944      * @param inputOffset
945      *            the offset in the input to start.
946      * @param inputLen
947      *            the length of the input to transform.
948      * @param output
949      *            the output buffer.
950      * @param outputOffset
951      *            the offset in the output buffer.
952      * @return the number of bytes placed in output.
953      * @throws ShortBufferException
954      *             if the size of the {@code output} buffer is too small.
955      * @throws IllegalStateException
956      *             if this cipher instance is not initialized for encryption or
957      *             decryption.
958      * @throws IllegalArgumentException
959      *             if the input is {@code null}, the output is {@code null}, or
960      *             if {@code inputOffset} and {@code inputLen} do not specify a
961      *             valid chunk in the input buffer.
962      */
update(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)963     public final int update(byte[] input, int inputOffset, int inputLen,
964             byte[] output, int outputOffset) throws ShortBufferException {
965         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
966             throw new IllegalStateException();
967         }
968         if (input == null) {
969             throw new IllegalArgumentException("input == null");
970         }
971         if (output == null) {
972             throw new IllegalArgumentException("output == null");
973         }
974         if (outputOffset < 0) {
975             throw new IllegalArgumentException("outputOffset < 0");
976         }
977         if (inputOffset < 0 || inputLen < 0 || inputLen > input.length
978                 || inputOffset > input.length - inputLen) {
979             throw new IllegalArgumentException("Incorrect inputOffset/inputLen parameters");
980         }
981         if (input.length == 0) {
982             return 0;
983         }
984         return spiImpl.engineUpdate(input, inputOffset, inputLen, output,
985                 outputOffset);
986     }
987 
988     /**
989      * Continues a multi-part transformation (encryption or decryption). The
990      * {@code input.remaining()} bytes starting at {@code input.position()} are
991      * transformed and stored in the {@code output} buffer.
992      * <p>
993      * If the {@code output.remaining()} is too small to hold the transformed
994      * bytes a {@code ShortBufferException} is thrown. Use
995      * {@link Cipher#getOutputSize getOutputSize} to check for the size of the
996      * output buffer.
997      *
998      * @param input
999      *            the input buffer to transform.
1000      * @param output
1001      *            the output buffer to store the result within.
1002      * @return the number of bytes stored in the output buffer.
1003      * @throws ShortBufferException
1004      *             if the size of the {@code output} buffer is too small.
1005      * @throws IllegalStateException
1006      *             if this cipher instance is not initialized for encryption or
1007      *             decryption.
1008      * @throws IllegalArgumentException
1009      *             if the input buffer and the output buffer are the identical
1010      *             object.
1011      */
update(ByteBuffer input, ByteBuffer output)1012     public final int update(ByteBuffer input, ByteBuffer output)
1013             throws ShortBufferException {
1014         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1015             throw new IllegalStateException();
1016         }
1017         if (input == output) {
1018             throw new IllegalArgumentException("input == output");
1019         }
1020         return spiImpl.engineUpdate(input, output);
1021     }
1022 
1023     /**
1024      * Finishes a multi-part transformation (encryption or decryption).
1025      * <p>
1026      * Processes any bytes that may have been buffered in previous {@code
1027      * update} calls.
1028      *
1029      * @return the final bytes from the transformation.
1030      * @throws IllegalBlockSizeException
1031      *             if the size of the resulting bytes is not a multiple of the
1032      *             cipher block size.
1033      * @throws BadPaddingException
1034      *             if the padding of the data does not match the padding scheme.
1035      * @throws IllegalStateException
1036      *             if this cipher instance is not initialized for encryption or
1037      *             decryption.
1038      */
doFinal()1039     public final byte[] doFinal() throws IllegalBlockSizeException,
1040             BadPaddingException {
1041         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1042             throw new IllegalStateException();
1043         }
1044         return spiImpl.engineDoFinal(null, 0, 0);
1045     }
1046 
1047     /**
1048      * Finishes a multi-part transformation (encryption or decryption).
1049      * <p>
1050      * Processes any bytes that may have been buffered in previous {@code
1051      * update} calls.
1052      * <p>
1053      * The final transformed bytes are stored in the {@code output} buffer.
1054      *
1055      * @param output
1056      *            the output buffer.
1057      * @param outputOffset
1058      *            the offset in the output buffer.
1059      * @return the number of bytes placed in the output buffer.
1060      * @throws IllegalBlockSizeException
1061      *             if the size of the resulting bytes is not a multiple of the
1062      *             cipher block size.
1063      * @throws ShortBufferException
1064      *             if the size of the {@code output} buffer is too small.
1065      * @throws BadPaddingException
1066      *             if the padding of the data does not match the padding scheme.
1067      * @throws IllegalStateException
1068      *             if this cipher instance is not initialized for encryption or
1069      *             decryption.
1070      */
doFinal(byte[] output, int outputOffset)1071     public final int doFinal(byte[] output, int outputOffset)
1072             throws IllegalBlockSizeException, ShortBufferException,
1073             BadPaddingException {
1074         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1075             throw new IllegalStateException();
1076         }
1077         if (outputOffset < 0) {
1078             throw new IllegalArgumentException("outputOffset < 0");
1079         }
1080         return spiImpl.engineDoFinal(null, 0, 0, output, outputOffset);
1081     }
1082 
1083     /**
1084      * Finishes a multi-part transformation (encryption or decryption).
1085      * <p>
1086      * Processes the bytes in {@code input} buffer, and any bytes that have been
1087      * buffered in previous {@code update} calls.
1088      *
1089      * @param input
1090      *            the input buffer.
1091      * @return the final bytes from the transformation.
1092      * @throws IllegalBlockSizeException
1093      *             if the size of the resulting bytes is not a multiple of the
1094      *             cipher block size.
1095      * @throws BadPaddingException
1096      *             if the padding of the data does not match the padding scheme.
1097      * @throws IllegalStateException
1098      *             if this cipher instance is not initialized for encryption or
1099      *             decryption.
1100      */
doFinal(byte[] input)1101     public final byte[] doFinal(byte[] input) throws IllegalBlockSizeException,
1102             BadPaddingException {
1103         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1104             throw new IllegalStateException();
1105         }
1106         return spiImpl.engineDoFinal(input, 0, input.length);
1107     }
1108 
1109     /**
1110      * Finishes a multi-part transformation (encryption or decryption).
1111      * <p>
1112      * Processes the {@code inputLen} bytes in {@code input} buffer at {@code
1113      * inputOffset}, and any bytes that have been buffered in previous {@code
1114      * update} calls.
1115      *
1116      * @param input
1117      *            the input buffer.
1118      * @param inputOffset
1119      *            the offset in the input buffer.
1120      * @param inputLen
1121      *            the length of the input
1122      * @return the final bytes from the transformation.
1123      * @throws IllegalBlockSizeException
1124      *             if the size of the resulting bytes is not a multiple of the
1125      *             cipher block size.
1126      * @throws BadPaddingException
1127      *             if the padding of the data does not match the padding scheme.
1128      * @throws IllegalStateException
1129      *             if this cipher instance is not initialized for encryption or
1130      *             decryption.
1131      * @throws IllegalArgumentException
1132      *             if {@code inputOffset} and {@code inputLen} do not specify an
1133      *             valid chunk in the input buffer.
1134      */
doFinal(byte[] input, int inputOffset, int inputLen)1135     public final byte[] doFinal(byte[] input, int inputOffset, int inputLen)
1136             throws IllegalBlockSizeException, BadPaddingException {
1137         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1138             throw new IllegalStateException();
1139         }
1140         if (inputOffset < 0 || inputLen < 0 || inputOffset + inputLen > input.length) {
1141             throw new IllegalArgumentException("Incorrect inputOffset/inputLen parameters");
1142         }
1143         return spiImpl.engineDoFinal(input, inputOffset, inputLen);
1144     }
1145 
1146     /**
1147      * Finishes a multi-part transformation (encryption or decryption).
1148      * <p>
1149      * Processes the {@code inputLen} bytes in {@code input} buffer at {@code
1150      * inputOffset}, and any bytes that have been buffered in previous {@code
1151      * update} calls.
1152      *
1153      * @param input
1154      *            the input buffer.
1155      * @param inputOffset
1156      *            the offset in the input buffer.
1157      * @param inputLen
1158      *            the length of the input.
1159      * @param output
1160      *            the output buffer for the transformed bytes.
1161      * @return the number of bytes placed in the output buffer.
1162      * @throws ShortBufferException
1163      *             if the size of the {@code output} buffer is too small.
1164      * @throws IllegalBlockSizeException
1165      *             if the size of the resulting bytes is not a multiple of the
1166      *             cipher block size.
1167      * @throws BadPaddingException
1168      *             if the padding of the data does not match the padding scheme.
1169      * @throws IllegalStateException
1170      *             if this cipher instance is not initialized for encryption or
1171      *             decryption.
1172      * @throws IllegalArgumentException
1173      *             if {@code inputOffset} and {@code inputLen} do not specify an
1174      *             valid chunk in the input buffer.
1175      */
doFinal(byte[] input, int inputOffset, int inputLen, byte[] output)1176     public final int doFinal(byte[] input, int inputOffset, int inputLen,
1177             byte[] output) throws ShortBufferException,
1178             IllegalBlockSizeException, BadPaddingException {
1179         return doFinal(input, inputOffset, inputLen, output, 0);
1180     }
1181 
1182     /**
1183      * Finishes a multi-part transformation (encryption or decryption).
1184      * <p>
1185      * Processes the {@code inputLen} bytes in {@code input} buffer at {@code
1186      * inputOffset}, and any bytes that have been buffered in previous {@code
1187      * update} calls.
1188      *
1189      * @param input
1190      *            the input buffer.
1191      * @param inputOffset
1192      *            the offset in the input buffer.
1193      * @param inputLen
1194      *            the length of the input.
1195      * @param output
1196      *            the output buffer for the transformed bytes.
1197      * @param outputOffset
1198      *            the offset in the output buffer.
1199      * @return the number of bytes placed in the output buffer.
1200      * @throws ShortBufferException
1201      *             if the size of the {@code output} buffer is too small.
1202      * @throws IllegalBlockSizeException
1203      *             if the size of the resulting bytes is not a multiple of the
1204      *             cipher block size.
1205      * @throws BadPaddingException
1206      *             if the padding of the data does not match the padding scheme.
1207      * @throws IllegalStateException
1208      *             if this cipher instance is not initialized for encryption or
1209      *             decryption.
1210      * @throws IllegalArgumentException
1211      *             if {@code inputOffset} and {@code inputLen} do not specify an
1212      *             valid chunk in the input buffer.
1213      */
doFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)1214     public final int doFinal(byte[] input, int inputOffset, int inputLen,
1215             byte[] output, int outputOffset) throws ShortBufferException,
1216             IllegalBlockSizeException, BadPaddingException {
1217         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1218             throw new IllegalStateException();
1219         }
1220         if (inputOffset < 0 || inputLen < 0 || inputOffset + inputLen > input.length) {
1221             throw new IllegalArgumentException("Incorrect inputOffset/inputLen parameters");
1222         }
1223         return spiImpl.engineDoFinal(input, inputOffset, inputLen, output,
1224                 outputOffset);
1225     }
1226 
1227     /**
1228      * Finishes a multi-part transformation (encryption or decryption).
1229      * <p>
1230      * Processes the {@code input.remaining()} bytes in {@code input} buffer at
1231      * {@code input.position()}, and any bytes that have been buffered in
1232      * previous {@code update} calls. The transformed bytes are placed into
1233      * {@code output} buffer.
1234      *
1235      * @param input
1236      *            the input buffer.
1237      * @param output
1238      *            the output buffer.
1239      * @return the number of bytes placed into the output buffer.
1240      * @throws ShortBufferException
1241      *             if the size of the {@code output} buffer is too small.
1242      * @throws IllegalBlockSizeException
1243      *             if the size of the resulting bytes is not a multiple of the
1244      *             cipher block size.
1245      * @throws BadPaddingException
1246      *             if the padding of the data does not match the padding scheme.
1247      * @throws IllegalArgumentException
1248      *             if the input buffer and the output buffer are the same
1249      *             object.
1250      * @throws IllegalStateException
1251      *             if this cipher instance is not initialized for encryption or
1252      *             decryption.
1253      */
doFinal(ByteBuffer input, ByteBuffer output)1254     public final int doFinal(ByteBuffer input, ByteBuffer output)
1255             throws ShortBufferException, IllegalBlockSizeException,
1256             BadPaddingException {
1257         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
1258             throw new IllegalStateException();
1259         }
1260         if (input == output) {
1261             throw new IllegalArgumentException("input == output");
1262         }
1263         return spiImpl.engineDoFinal(input, output);
1264     }
1265 
1266     /**
1267      * Wraps a key using this cipher instance.
1268      *
1269      * @param key
1270      *            the key to wrap.
1271      * @return the wrapped key.
1272      * @throws IllegalBlockSizeException
1273      *             if the size of the resulting bytes is not a multiple of the
1274      *             cipher block size.
1275      * @throws InvalidKeyException
1276      *             if this cipher instance can not wrap this key.
1277      * @throws IllegalStateException
1278      *             if this cipher instance is not initialized for wrapping.
1279      */
wrap(Key key)1280     public final byte[] wrap(Key key) throws IllegalBlockSizeException,
1281             InvalidKeyException {
1282         if (mode != WRAP_MODE) {
1283             throw new IllegalStateException();
1284         }
1285         return spiImpl.engineWrap(key);
1286     }
1287 
1288     /**
1289      * Unwraps a key using this cipher instance.
1290      *
1291      * @param wrappedKey
1292      *            the wrapped key to unwrap.
1293      * @param wrappedKeyAlgorithm
1294      *            the algorithm for the wrapped key.
1295      * @param wrappedKeyType
1296      *            the type of the wrapped key (one of: {@code SECRET_KEY
1297      *            <code>, <code>PRIVATE_KEY} or {@code PUBLIC_KEY})
1298      * @return the unwrapped key
1299      * @throws InvalidKeyException
1300      *             if the {@code wrappedKey} can not be unwrapped to a key of
1301      *             type {@code wrappedKeyType} for the {@code
1302      *             wrappedKeyAlgorithm}.
1303      * @throws NoSuchAlgorithmException
1304      *             if no provider can be found that can create a key of type
1305      *             {@code wrappedKeyType} for the {@code wrappedKeyAlgorithm}.
1306      * @throws IllegalStateException
1307      *             if this cipher instance is not initialized for unwrapping.
1308      */
unwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType)1309     public final Key unwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
1310             int wrappedKeyType) throws InvalidKeyException,
1311             NoSuchAlgorithmException {
1312         if (mode != UNWRAP_MODE) {
1313             throw new IllegalStateException();
1314         }
1315         return spiImpl.engineUnwrap(wrappedKey, wrappedKeyAlgorithm,
1316                 wrappedKeyType);
1317     }
1318 
1319     /**
1320      * Returns the maximum key length for the specified transformation.
1321      *
1322      * @param transformation
1323      *            the transformation name.
1324      * @return the maximum key length, currently {@code Integer.MAX_VALUE}.
1325      * @throws NoSuchAlgorithmException
1326      *             if no provider for the specified {@code transformation} can
1327      *             be found.
1328      * @throws NullPointerException
1329      *             if {@code transformation} is {@code null}.
1330      */
getMaxAllowedKeyLength(String transformation)1331     public static final int getMaxAllowedKeyLength(String transformation)
1332             throws NoSuchAlgorithmException {
1333         if (transformation == null) {
1334             throw new NullPointerException();
1335         }
1336         checkTransformation(transformation);
1337         //FIXME jurisdiction policy files
1338         return Integer.MAX_VALUE;
1339     }
1340 
1341     /**
1342      * Returns the maximum cipher parameter value for the specified
1343      * transformation. If there is no maximum limit, {@code null} is returned.
1344      *
1345      * @param transformation
1346      *            the transformation name.
1347      * @return a parameter spec holding the maximum value or {@code null}.
1348      *         Currently {@code null}.
1349      * @throws NoSuchAlgorithmException
1350      *             if no provider for the specified {@code transformation} can
1351      *             be found.
1352      * @throws NullPointerException
1353      *             if {@code transformation} is {@code null}.
1354      */
getMaxAllowedParameterSpec( String transformation)1355     public static final AlgorithmParameterSpec getMaxAllowedParameterSpec(
1356             String transformation) throws NoSuchAlgorithmException {
1357         if (transformation == null) {
1358             throw new NullPointerException();
1359         }
1360         checkTransformation(transformation);
1361         //FIXME jurisdiction policy files
1362         return null;
1363     }
1364 }
1365