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