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