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 org.apache.harmony.crypto.internal.NullCipherSpi;
     36 import org.apache.harmony.security.fortress.Engine;
     37 
     38 /**
     39  * This class provides access to implementations of cryptographic ciphers for
     40  * encryption and decryption. Cipher classes can not be instantiated directly,
     41  * one has to call the Cipher's {@code getInstance} method with the name of a
     42  * requested transformation, optionally with a provider. A transformation
     43  * specifies an operation (or a set of operations) as a string in the form:
     44  * <ul>
     45  * <li><i>"algorithm/mode/padding"</i></li> or
     46  * <li><i>"algorithm"</i></li>
     47  * </ul>
     48  * <i>algorithm</i> is the name of a cryptographic algorithm, <i>mode</i> is the
     49  * name of a feedback mode and <i>padding</i> is the name of a padding scheme.
     50  * If <i>mode</i> and/or <i>padding</i> values are omitted, provider specific
     51  * default values will be used.
     52  * <p>
     53  * A valid transformation would be:
     54  * <ul>
     55  * {@code Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");}
     56  * </ul>
     57  * When a block cipher is requested in in stream cipher mode, the number of bits
     58  * to be processed at a time can be optionally specified by appending it to the
     59  * mode name. e.g. <i>"AES/CFB8/NoPadding"</i>. If no number is specified, a
     60  * provider specific default value is used.
     61  */
     62 public class Cipher {
     63 
     64     /**
     65      * Constant for decryption operation mode.
     66      */
     67     public static final int DECRYPT_MODE = 2;
     68 
     69     /**
     70      * Constant for encryption operation mode.
     71      */
     72     public static final int ENCRYPT_MODE = 1;
     73 
     74     /**
     75      * Constant indicating that the key to be unwrapped is a private key.
     76      */
     77     public static final int PRIVATE_KEY = 2;
     78 
     79     /**
     80      * Constant indicating that the key to be unwrapped is a public key.
     81      */
     82     public static final int PUBLIC_KEY = 1;
     83 
     84     /**
     85      * Constant indicating that the key to be unwrapped is a secret key.
     86      */
     87     public static final int SECRET_KEY = 3;
     88 
     89     /**
     90      * Constant for key unwrapping operation mode.
     91      */
     92     public static final int UNWRAP_MODE = 4;
     93 
     94     /**
     95      * Constant for key wrapping operation mode.
     96      */
     97     public static final int WRAP_MODE = 3;
     98 
     99     private int mode;
    100 
    101     /**
    102      * The service name.
    103      */
    104     private static final String SERVICE = "Cipher";
    105 
    106     /**
    107      * Used to access common engine functionality.
    108      */
    109     private static final Engine ENGINE = new Engine(SERVICE);
    110 
    111     /**
    112      * The provider.
    113      */
    114     private Provider provider;
    115 
    116     /**
    117      * The SPI implementation.
    118      */
    119     private CipherSpi spiImpl;
    120 
    121     /**
    122      * The transformation.
    123      */
    124     private String transformation;
    125 
    126     private static SecureRandom secureRandom;
    127 
    128     /**
    129      * Creates a new Cipher instance.
    130      *
    131      * @param cipherSpi
    132      *            the implementation delegate of the cipher.
    133      * @param provider
    134      *            the provider of the implementation of this cipher.
    135      * @param transformation
    136      *            the name of the transformation that this cipher performs.
    137      * @throws NullPointerException
    138      *             if either cipherSpi is {@code null} or provider is {@code
    139      *             null} and {@code cipherSpi} is a {@code NullCipherSpi}.
    140      */
    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 {@code 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      * Continues a multi-part transformation (encryption or decryption) with
   1030      * Authenticated Additional Data (AAD). AAD may only be added after the
   1031      * {@code Cipher} is initialized and before any data is passed to the
   1032      * instance.
   1033      * <p>
   1034      * This is only usable with cipher modes that support Authenticated
   1035      * Encryption with Additional Data (AEAD) such as Galois/Counter Mode (GCM).
   1036      *
   1037      * @param input bytes of AAD to use with the cipher
   1038      * @throws IllegalStateException
   1039      *             if this cipher instance is not initialized for encryption or
   1040      *             decryption.
   1041      * @throws IllegalArgumentException
   1042      *             if {@code input} is {@code null}
   1043      * @throws UnsupportedOperationException if the cipher does not support AEAD
   1044      * @since 1.7
   1045      */
   1046     public final void updateAAD(byte[] input) {
   1047         if (input == null) {
   1048             throw new IllegalArgumentException("input == null");
   1049         }
   1050         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
   1051             throw new IllegalStateException();
   1052         }
   1053         if (input.length == 0) {
   1054             return;
   1055         }
   1056         spiImpl.engineUpdateAAD(input, 0, input.length);
   1057     }
   1058 
   1059     /**
   1060      * Continues a multi-part transformation (encryption or decryption) with
   1061      * Authenticated Additional Data (AAD). AAD may only be added after the
   1062      * {@code Cipher} is initialized and before any data is passed to the
   1063      * instance.
   1064      * <p>
   1065      * This is only usable with cipher modes that support Authenticated
   1066      * Encryption with Additional Data (AEAD) such as Galois/Counter Mode (GCM).
   1067      *
   1068      * @param input bytes of AAD to use with the cipher
   1069      * @param inputOffset offset within bytes of additional data to add to cipher
   1070      * @param inputLen length of bytes of additional data to add to cipher
   1071      * @throws IllegalStateException
   1072      *             if this cipher instance is not initialized for encryption or
   1073      *             decryption.
   1074      * @throws IllegalArgumentException
   1075      *             if {@code input} is {@code null}, or if {@code inputOffset} and
   1076      *             {@code inputLen} do not specify a valid chunk in the input
   1077      *             buffer.
   1078      * @throws UnsupportedOperationException if the cipher does not support AEAD
   1079      * @since 1.7
   1080      */
   1081     public final void updateAAD(byte[] input, int inputOffset, int inputLen) {
   1082         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
   1083             throw new IllegalStateException();
   1084         }
   1085         if (input == null) {
   1086             throw new IllegalArgumentException("input == null");
   1087         }
   1088         checkInputOffsetAndCount(input.length, inputOffset, inputLen);
   1089         if (input.length == 0) {
   1090             return;
   1091         }
   1092         spiImpl.engineUpdateAAD(input, inputOffset, inputLen);
   1093     }
   1094 
   1095     /**
   1096      * Continues a multi-part transformation (encryption or decryption) with
   1097      * Authenticated Additional Data (AAD). AAD may only be added after the
   1098      * {@code Cipher} is initialized and before any data is passed to the
   1099      * instance.
   1100      * <p>
   1101      * This is only usable with cipher modes that support Authenticated
   1102      * Encryption with Additional Data (AEAD) such as Galois/Counter Mode (GCM).
   1103      *
   1104      * @param input buffer of AAD to be used
   1105      * @throws IllegalStateException
   1106      *             if this cipher instance is not initialized for encryption or
   1107      *             decryption.
   1108      * @throws UnsupportedOperationException if the cipher does not support AEAD
   1109      * @since 1.7
   1110      */
   1111     public final void updateAAD(ByteBuffer input) {
   1112         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
   1113             throw new IllegalStateException("Cipher is not initialized");
   1114         }
   1115         if (input == null) {
   1116             throw new IllegalArgumentException("input == null");
   1117         }
   1118         spiImpl.engineUpdateAAD(input);
   1119     }
   1120 
   1121     /**
   1122      * Finishes a multi-part transformation (encryption or decryption).
   1123      * <p>
   1124      * Processes any bytes that may have been buffered in previous {@code
   1125      * update} calls.
   1126      *
   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      */
   1137     public final byte[] doFinal() throws IllegalBlockSizeException,
   1138             BadPaddingException {
   1139         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
   1140             throw new IllegalStateException();
   1141         }
   1142         return spiImpl.engineDoFinal(null, 0, 0);
   1143     }
   1144 
   1145     /**
   1146      * Finishes a multi-part transformation (encryption or decryption).
   1147      * <p>
   1148      * Processes any bytes that may have been buffered in previous {@code
   1149      * update} calls.
   1150      * <p>
   1151      * The final transformed bytes are stored in the {@code output} buffer.
   1152      *
   1153      * @param output
   1154      *            the output buffer.
   1155      * @param outputOffset
   1156      *            the offset in the output buffer.
   1157      * @return the number of bytes placed in the output buffer.
   1158      * @throws IllegalBlockSizeException
   1159      *             if the size of the resulting bytes is not a multiple of the
   1160      *             cipher block size.
   1161      * @throws ShortBufferException
   1162      *             if the size of the {@code output} buffer is too small.
   1163      * @throws BadPaddingException
   1164      *             if the padding of the data does not match the padding scheme.
   1165      * @throws IllegalStateException
   1166      *             if this cipher instance is not initialized for encryption or
   1167      *             decryption.
   1168      */
   1169     public final int doFinal(byte[] output, int outputOffset)
   1170             throws IllegalBlockSizeException, ShortBufferException,
   1171             BadPaddingException {
   1172         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
   1173             throw new IllegalStateException();
   1174         }
   1175         if (outputOffset < 0) {
   1176             throw new IllegalArgumentException("outputOffset < 0. outputOffset=" + outputOffset);
   1177         }
   1178         return spiImpl.engineDoFinal(null, 0, 0, output, outputOffset);
   1179     }
   1180 
   1181     /**
   1182      * Finishes a multi-part transformation (encryption or decryption).
   1183      * <p>
   1184      * Processes the bytes in {@code input} buffer, and any bytes that have been
   1185      * buffered in previous {@code update} calls.
   1186      *
   1187      * @param input
   1188      *            the input buffer.
   1189      * @return the final bytes from the transformation.
   1190      * @throws IllegalBlockSizeException
   1191      *             if the size of the resulting bytes is not a multiple of the
   1192      *             cipher block size.
   1193      * @throws BadPaddingException
   1194      *             if the padding of the data does not match the padding scheme.
   1195      * @throws IllegalStateException
   1196      *             if this cipher instance is not initialized for encryption or
   1197      *             decryption.
   1198      */
   1199     public final byte[] doFinal(byte[] input) throws IllegalBlockSizeException,
   1200             BadPaddingException {
   1201         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
   1202             throw new IllegalStateException();
   1203         }
   1204         return spiImpl.engineDoFinal(input, 0, input.length);
   1205     }
   1206 
   1207     /**
   1208      * Finishes a multi-part transformation (encryption or decryption).
   1209      * <p>
   1210      * Processes the {@code inputLen} bytes in {@code input} buffer at {@code
   1211      * inputOffset}, and any bytes that have been buffered in previous {@code
   1212      * update} calls.
   1213      *
   1214      * @param input
   1215      *            the input buffer.
   1216      * @param inputOffset
   1217      *            the offset in the input buffer.
   1218      * @param inputLen
   1219      *            the length of the input
   1220      * @return the final bytes from the transformation.
   1221      * @throws IllegalBlockSizeException
   1222      *             if the size of the resulting bytes is not a multiple of the
   1223      *             cipher block size.
   1224      * @throws BadPaddingException
   1225      *             if the padding of the data does not match the padding scheme.
   1226      * @throws IllegalStateException
   1227      *             if this cipher instance is not initialized for encryption or
   1228      *             decryption.
   1229      * @throws IllegalArgumentException
   1230      *             if {@code inputOffset} and {@code inputLen} do not specify an
   1231      *             valid chunk in the input buffer.
   1232      */
   1233     public final byte[] doFinal(byte[] input, int inputOffset, int inputLen)
   1234             throws IllegalBlockSizeException, BadPaddingException {
   1235         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
   1236             throw new IllegalStateException();
   1237         }
   1238         checkInputOffsetAndCount(input.length, inputOffset, inputLen);
   1239         return spiImpl.engineDoFinal(input, inputOffset, inputLen);
   1240     }
   1241 
   1242     /**
   1243      * Finishes a multi-part transformation (encryption or decryption).
   1244      * <p>
   1245      * Processes the {@code inputLen} bytes in {@code input} buffer at {@code
   1246      * inputOffset}, and any bytes that have been buffered in previous {@code
   1247      * update} calls.
   1248      *
   1249      * @param input
   1250      *            the input buffer.
   1251      * @param inputOffset
   1252      *            the offset in the input buffer.
   1253      * @param inputLen
   1254      *            the length of the input.
   1255      * @param output
   1256      *            the output buffer for the transformed bytes.
   1257      * @return the number of bytes placed in the output buffer.
   1258      * @throws ShortBufferException
   1259      *             if the size of the {@code output} buffer is too small.
   1260      * @throws IllegalBlockSizeException
   1261      *             if the size of the resulting bytes is not a multiple of the
   1262      *             cipher block size.
   1263      * @throws BadPaddingException
   1264      *             if the padding of the data does not match the padding scheme.
   1265      * @throws IllegalStateException
   1266      *             if this cipher instance is not initialized for encryption or
   1267      *             decryption.
   1268      * @throws IllegalArgumentException
   1269      *             if {@code inputOffset} and {@code inputLen} do not specify an
   1270      *             valid chunk in the input buffer.
   1271      */
   1272     public final int doFinal(byte[] input, int inputOffset, int inputLen,
   1273             byte[] output) throws ShortBufferException,
   1274             IllegalBlockSizeException, BadPaddingException {
   1275         return doFinal(input, inputOffset, inputLen, output, 0);
   1276     }
   1277 
   1278     /**
   1279      * Finishes a multi-part transformation (encryption or decryption).
   1280      * <p>
   1281      * Processes the {@code inputLen} bytes in {@code input} buffer at {@code
   1282      * inputOffset}, and any bytes that have been buffered in previous {@code
   1283      * update} calls.
   1284      *
   1285      * @param input
   1286      *            the input buffer.
   1287      * @param inputOffset
   1288      *            the offset in the input buffer.
   1289      * @param inputLen
   1290      *            the length of the input.
   1291      * @param output
   1292      *            the output buffer for the transformed bytes.
   1293      * @param outputOffset
   1294      *            the offset in the output buffer.
   1295      * @return the number of bytes placed in the output buffer.
   1296      * @throws ShortBufferException
   1297      *             if the size of the {@code output} buffer is too small.
   1298      * @throws IllegalBlockSizeException
   1299      *             if the size of the resulting bytes is not a multiple of the
   1300      *             cipher block size.
   1301      * @throws BadPaddingException
   1302      *             if the padding of the data does not match the padding scheme.
   1303      * @throws IllegalStateException
   1304      *             if this cipher instance is not initialized for encryption or
   1305      *             decryption.
   1306      * @throws IllegalArgumentException
   1307      *             if {@code inputOffset} and {@code inputLen} do not specify an
   1308      *             valid chunk in the input buffer.
   1309      */
   1310     public final int doFinal(byte[] input, int inputOffset, int inputLen,
   1311             byte[] output, int outputOffset) throws ShortBufferException,
   1312             IllegalBlockSizeException, BadPaddingException {
   1313         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
   1314             throw new IllegalStateException();
   1315         }
   1316         checkInputOffsetAndCount(input.length, inputOffset, inputLen);
   1317         return spiImpl.engineDoFinal(input, inputOffset, inputLen, output,
   1318                 outputOffset);
   1319     }
   1320 
   1321     /**
   1322      * Finishes a multi-part transformation (encryption or decryption).
   1323      * <p>
   1324      * Processes the {@code input.remaining()} bytes in {@code input} buffer at
   1325      * {@code input.position()}, and any bytes that have been buffered in
   1326      * previous {@code update} calls. The transformed bytes are placed into
   1327      * {@code output} buffer.
   1328      *
   1329      * @param input
   1330      *            the input buffer.
   1331      * @param output
   1332      *            the output buffer.
   1333      * @return the number of bytes placed into the output buffer.
   1334      * @throws ShortBufferException
   1335      *             if the size of the {@code output} buffer is too small.
   1336      * @throws IllegalBlockSizeException
   1337      *             if the size of the resulting bytes is not a multiple of the
   1338      *             cipher block size.
   1339      * @throws BadPaddingException
   1340      *             if the padding of the data does not match the padding scheme.
   1341      * @throws IllegalArgumentException
   1342      *             if the input buffer and the output buffer are the same
   1343      *             object.
   1344      * @throws IllegalStateException
   1345      *             if this cipher instance is not initialized for encryption or
   1346      *             decryption.
   1347      */
   1348     public final int doFinal(ByteBuffer input, ByteBuffer output)
   1349             throws ShortBufferException, IllegalBlockSizeException,
   1350             BadPaddingException {
   1351         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
   1352             throw new IllegalStateException();
   1353         }
   1354         if (input == output) {
   1355             throw new IllegalArgumentException("input == output");
   1356         }
   1357         return spiImpl.engineDoFinal(input, output);
   1358     }
   1359 
   1360     /**
   1361      * Wraps a key using this cipher instance.
   1362      *
   1363      * @param key
   1364      *            the key to wrap.
   1365      * @return the wrapped key.
   1366      * @throws IllegalBlockSizeException
   1367      *             if the size of the resulting bytes is not a multiple of the
   1368      *             cipher block size.
   1369      * @throws InvalidKeyException
   1370      *             if this cipher instance can not wrap this key.
   1371      * @throws IllegalStateException
   1372      *             if this cipher instance is not initialized for wrapping.
   1373      */
   1374     public final byte[] wrap(Key key) throws IllegalBlockSizeException,
   1375             InvalidKeyException {
   1376         if (mode != WRAP_MODE) {
   1377             throw new IllegalStateException();
   1378         }
   1379         return spiImpl.engineWrap(key);
   1380     }
   1381 
   1382     /**
   1383      * Unwraps a key using this cipher instance.
   1384      *
   1385      * @param wrappedKey
   1386      *            the wrapped key to unwrap.
   1387      * @param wrappedKeyAlgorithm
   1388      *            the algorithm for the wrapped key.
   1389      * @param wrappedKeyType
   1390      *            the type of the wrapped key (one of: {@code SECRET_KEY
   1391      *            <code>, <code>PRIVATE_KEY} or {@code PUBLIC_KEY})
   1392      * @return the unwrapped key
   1393      * @throws InvalidKeyException
   1394      *             if the {@code wrappedKey} can not be unwrapped to a key of
   1395      *             type {@code wrappedKeyType} for the {@code
   1396      *             wrappedKeyAlgorithm}.
   1397      * @throws NoSuchAlgorithmException
   1398      *             if no provider can be found that can create a key of type
   1399      *             {@code wrappedKeyType} for the {@code wrappedKeyAlgorithm}.
   1400      * @throws IllegalStateException
   1401      *             if this cipher instance is not initialized for unwrapping.
   1402      */
   1403     public final Key unwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
   1404             int wrappedKeyType) throws InvalidKeyException,
   1405             NoSuchAlgorithmException {
   1406         if (mode != UNWRAP_MODE) {
   1407             throw new IllegalStateException();
   1408         }
   1409         return spiImpl.engineUnwrap(wrappedKey, wrappedKeyAlgorithm,
   1410                 wrappedKeyType);
   1411     }
   1412 
   1413     /**
   1414      * Returns the maximum key length for the specified transformation.
   1415      *
   1416      * @param transformation
   1417      *            the transformation name.
   1418      * @return the maximum key length, currently {@code Integer.MAX_VALUE}.
   1419      * @throws NoSuchAlgorithmException
   1420      *             if no provider for the specified {@code transformation} can
   1421      *             be found.
   1422      * @throws NullPointerException
   1423      *             if {@code transformation} is {@code null}.
   1424      */
   1425     public static final int getMaxAllowedKeyLength(String transformation)
   1426             throws NoSuchAlgorithmException {
   1427         if (transformation == null) {
   1428             throw new NullPointerException("transformation == null");
   1429         }
   1430         checkTransformation(transformation);
   1431         //FIXME jurisdiction policy files
   1432         return Integer.MAX_VALUE;
   1433     }
   1434 
   1435     /**
   1436      * Returns the maximum cipher parameter value for the specified
   1437      * transformation. If there is no maximum limit, {@code null} is returned.
   1438      *
   1439      * @param transformation
   1440      *            the transformation name.
   1441      * @return a parameter spec holding the maximum value or {@code null}.
   1442      *         Currently {@code null}.
   1443      * @throws NoSuchAlgorithmException
   1444      *             if no provider for the specified {@code transformation} can
   1445      *             be found.
   1446      * @throws NullPointerException
   1447      *             if {@code transformation} is {@code null}.
   1448      */
   1449     public static final AlgorithmParameterSpec getMaxAllowedParameterSpec(
   1450             String transformation) throws NoSuchAlgorithmException {
   1451         if (transformation == null) {
   1452             throw new NullPointerException("transformation == null");
   1453         }
   1454         checkTransformation(transformation);
   1455         //FIXME jurisdiction policy files
   1456         return null;
   1457     }
   1458 }
   1459