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