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