/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package javax.crypto; import java.nio.ByteBuffer; import java.security.AlgorithmParameters; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.InvalidParameterException; import java.security.Key; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.Provider; import java.security.SecureRandom; import java.security.Security; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.security.spec.AlgorithmParameterSpec; import java.util.Set; import org.apache.harmony.crypto.internal.NullCipherSpi; import org.apache.harmony.security.fortress.Engine; /** * This class provides access to implementations of cryptographic ciphers for * encryption and decryption. Cipher classes can not be instantiated directly, * one has to call the Cipher's {@code getInstance} method with the name of a * requested transformation, optionally with a provider. A transformation * specifies an operation (or a set of operations) as a string in the form: * * algorithm is the name of a cryptographic algorithm, mode is the * name of a feedback mode and padding is the name of a padding scheme. * If mode and/or padding values are omitted, provider specific * default values will be used. *

* A valid transformation would be: *

* When a block cipher is requested in in stream cipher mode, the number of bits * to be processed at a time can be optionally specified by appending it to the * mode name. e.g. "AES/CFB8/NoPadding". If no number is specified, a * provider specific default value is used. */ public class Cipher { /** * Constant for decryption operation mode. */ public static final int DECRYPT_MODE = 2; /** * Constant for encryption operation mode. */ public static final int ENCRYPT_MODE = 1; /** * Constant indicating that the key to be unwrapped is a private key. */ public static final int PRIVATE_KEY = 2; /** * Constant indicating that the key to be unwrapped is a public key. */ public static final int PUBLIC_KEY = 1; /** * Constant indicating that the key to be unwrapped is a secret key. */ public static final int SECRET_KEY = 3; /** * Constant for key unwrapping operation mode. */ public static final int UNWRAP_MODE = 4; /** * Constant for key wrapping operation mode. */ public static final int WRAP_MODE = 3; private int mode; /** * The service name. */ private static final String SERVICE = "Cipher"; /** * Used to access common engine functionality. */ private static final Engine ENGINE = new Engine(SERVICE); /** * The provider. */ private Provider provider; /** * The SPI implementation. */ private CipherSpi spiImpl; /** * The transformation. */ private String transformation; private static SecureRandom secureRandom; /** * Creates a new Cipher instance. * * @param cipherSpi * the implementation delegate of the cipher. * @param provider * the provider of the implementation of this cipher. * @param transformation * the name of the transformation that this cipher performs. * @throws NullPointerException * if either cipherSpi is {@code null} or provider is {@code * null} and {@code cipherSpi} is a {@code NullCipherSpi}. */ protected Cipher(CipherSpi cipherSpi, Provider provider, String transformation) { if (cipherSpi == null) { throw new NullPointerException("cipherSpi == null"); } if (!(cipherSpi instanceof NullCipherSpi) && provider == null) { throw new NullPointerException("provider == null"); } this.provider = provider; this.transformation = transformation; this.spiImpl = cipherSpi; } /** * Creates a new Cipher for the specified transformation. The installed * providers are searched in order for an implementation of the specified * transformation. The first found provider providing the transformation is * used to create the cipher. If no provider is found an exception is * thrown. * * @param transformation * the name of the transformation to create a cipher for. * @return a cipher for the requested transformation. * @throws NoSuchAlgorithmException * if no installed provider can provide the * transformation, or it is {@code null}, empty or in an * invalid format. * @throws NoSuchPaddingException * if no installed provider can provide the padding scheme in * the transformation. */ public static final Cipher getInstance(String transformation) throws NoSuchAlgorithmException, NoSuchPaddingException { return getCipher(transformation, null); } /** * Creates a new cipher for the specified transformation provided by the * specified provider. * * @param transformation * the name of the transformation to create a cipher for. * @param provider * the name of the provider to ask for the transformation. * @return a cipher for the requested transformation. * @throws NoSuchAlgorithmException * if the specified provider can not provide the * transformation, or it is {@code null}, empty or in an * invalid format. * @throws NoSuchProviderException * if no provider with the specified name can be found. * @throws NoSuchPaddingException * if the requested padding scheme in the transformation * is not available. * @throws IllegalArgumentException * if the specified provider is {@code null}. */ public static final Cipher getInstance(String transformation, String provider) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException { if (provider == null) { throw new IllegalArgumentException("provider == null"); } Provider p = Security.getProvider(provider); if (p == null) { throw new NoSuchProviderException("Provider not available: " + provider); } return getInstance(transformation, p); } /** * Creates a new cipher for the specified transformation. * * @param transformation * the name of the transformation to create a cipher for. * @param provider * the provider to ask for the transformation. * @return a cipher for the requested transformation. * @throws NoSuchAlgorithmException * if the specified provider can not provide the * transformation, or it is {@code null}, empty or in an * invalid format. * @throws NoSuchPaddingException * if the requested padding scheme in the transformation * is not available. * @throws IllegalArgumentException * if the provider is {@code null}. */ public static final Cipher getInstance(String transformation, Provider provider) throws NoSuchAlgorithmException, NoSuchPaddingException { if (provider == null) { throw new IllegalArgumentException("provider == null"); } Cipher c = getCipher(transformation, provider); return c; } private static NoSuchAlgorithmException invalidTransformation(String transformation) throws NoSuchAlgorithmException { throw new NoSuchAlgorithmException("Invalid transformation: " + transformation); } /** * Find appropriate Cipher according the specification rules * * @param transformation * @param provider * @return * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException */ private static synchronized Cipher getCipher(String transformation, Provider provider) throws NoSuchAlgorithmException, NoSuchPaddingException { if (transformation == null || transformation.isEmpty()) { throw invalidTransformation(transformation); } String[] transf = checkTransformation(transformation); boolean needSetPadding = false; boolean needSetMode = false; Object engineSpi = null; Provider engineProvider = provider; if (transf[1] == null && transf[2] == null) { // "algorithm" if (provider == null) { Engine.SpiAndProvider sap = ENGINE.getInstance(transf[0], null); engineSpi = sap.spi; engineProvider = sap.provider; } else { engineSpi = ENGINE.getInstance(transf[0], provider, null); } } else { String[] searchOrder = { transf[0] + "/" + transf[1] + "/" + transf[2], // "algorithm/mode/padding" transf[0] + "/" + transf[1], // "algorithm/mode" transf[0] + "//" + transf[2], // "algorithm//padding" transf[0] // "algorithm" }; int i; for (i = 0; i < searchOrder.length; i++) { try { if (provider == null) { Engine.SpiAndProvider sap = ENGINE.getInstance(searchOrder[i], null); engineSpi = sap.spi; engineProvider = sap.provider; } else { engineSpi = ENGINE.getInstance(searchOrder[i], provider, null); } break; } catch (NoSuchAlgorithmException e) { if (i == searchOrder.length-1) { throw new NoSuchAlgorithmException(transformation, e); } } } switch (i) { case 1: // "algorithm/mode" needSetPadding = true; break; case 2: // "algorithm//padding" needSetMode = true; break; case 3: // "algorithm" needSetPadding = true; needSetMode = true; } } if (engineSpi == null || engineProvider == null) { throw new NoSuchAlgorithmException(transformation); } if (!(engineSpi instanceof CipherSpi)) { throw new NoSuchAlgorithmException(engineSpi.getClass().getName()); } CipherSpi cspi = (CipherSpi) engineSpi; Cipher c = new Cipher(cspi, engineProvider, transformation); if (needSetMode) { c.spiImpl.engineSetMode(transf[1]); } if (needSetPadding) { c.spiImpl.engineSetPadding(transf[2]); } return c; } private static String[] checkTransformation(String transformation) throws NoSuchAlgorithmException { // ignore an extra prefix / characters such as in // "/DES/CBC/PKCS5Paddin" http://b/3387688 if (transformation.startsWith("/")) { transformation = transformation.substring(1); } // 'transformation' should be of the form "algorithm/mode/padding". String[] pieces = transformation.split("/"); if (pieces.length > 3) { throw invalidTransformation(transformation); } // Empty or missing pieces are represented by null. String[] result = new String[3]; for (int i = 0; i < pieces.length; ++i) { String piece = pieces[i].trim(); if (!piece.isEmpty()) { result[i] = piece; } } // You MUST specify an algorithm. if (result[0] == null) { throw invalidTransformation(transformation); } if (!(result[1] == null && result[2] == null) && (result[1] == null || result[2] == null)) { throw invalidTransformation(transformation); } return result; } /** * Returns the provider of this cipher instance. * * @return the provider of this cipher instance. */ public final Provider getProvider() { return provider; } /** * Returns the name of the algorithm of this cipher instance. *

* This is the name of the transformation argument used in the * {@code getInstance} call creating this object. * * @return the name of the algorithm of this cipher instance. */ public final String getAlgorithm() { return transformation; } /** * Returns this ciphers block size (in bytes). * * @return this ciphers block size. */ public final int getBlockSize() { return spiImpl.engineGetBlockSize(); } /** * Returns the length in bytes an output buffer needs to be when this cipher * is updated with {@code inputLen} bytes. * * @param inputLen * the number of bytes of the input. * @return the output buffer length for the input length. * @throws IllegalStateException * if this cipher instance is in an invalid state. */ public final int getOutputSize(int inputLen) { if (mode == 0) { throw new IllegalStateException("Cipher has not yet been initialized"); } return spiImpl.engineGetOutputSize(inputLen); } /** * Returns the initialization vector for this cipher instance. * * @return the initialization vector for this cipher instance. */ public final byte[] getIV() { return spiImpl.engineGetIV(); } /** * Returns the parameters that where used to create this cipher instance. *

* These may be a the same parameters that were used to create this cipher * instance, or may be a combination of default and random parameters, * depending on the underlying cipher implementation. * * @return the parameters that where used to create this cipher instance, or * {@code null} if this cipher instance does not have any * parameters. */ public final AlgorithmParameters getParameters() { return spiImpl.engineGetParameters(); } /** * Returns the exemption mechanism associated with this cipher. * * @return currently {@code null} */ public final ExemptionMechanism getExemptionMechanism() { //FIXME implement getExemptionMechanism // try { // return ExemptionMechanism.getInstance(transformation, provider); // } catch (NoSuchAlgorithmException e) { return null; // } } /** * Initializes this cipher instance with the specified key. *

* The cipher is initialized for the specified operational mode (one of: * encryption, decryption, key wrapping or key unwrapping) depending on * {@code opmode}. *

* If this cipher instance needs any algorithm parameters or random values * that the specified key can not provide, the underlying implementation of * this cipher is supposed to generate the required parameters (using its * provider or random values). *

* When a cipher instance is initialized by a call to any of the {@code * init} methods, the state of the instance is overridden, meaning that it * is equivalent to creating a new instance and calling its {@code init} * method. * * @param opmode * the operation this cipher instance should be initialized for * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code * WRAP_MODE} or {@code UNWRAP_MODE}). * @param key * the input key for the operation. * @throws InvalidKeyException * if the specified key can not be used to initialize this * cipher instance. */ public final void init(int opmode, Key key) throws InvalidKeyException { if (secureRandom == null) { // In theory it might be thread-unsafe but in the given case it's OK // since it does not matter which SecureRandom instance is passed // to the init() secureRandom = new SecureRandom(); } init(opmode, key, secureRandom); } /** * Initializes this cipher instance with the specified key and a source of * randomness. *

* The cipher is initialized for the specified operational mode (one of: * encryption, decryption, key wrapping or key unwrapping) depending on * {@code opmode}. *

* If this cipher instance needs any algorithm parameters or random values * that the specified key can not provide, the underlying implementation of * this cipher is supposed to generate the required parameters (using its * provider or random values). Random values are generated using {@code * random}; *

* When a cipher instance is initialized by a call to any of the {@code * init} methods, the state of the instance is overridden, means it is * equivalent to creating a new instance and calling it {@code init} method. * * @param opmode * the operation this cipher instance should be initialized for * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code * WRAP_MODE} or {@code UNWRAP_MODE}). * @param key * the input key for the operation. * @param random * the source of randomness to use. * @throws InvalidKeyException * if the specified key can not be used to initialize this * cipher instance. * @throws InvalidParameterException * if the specified opmode is invalid. */ public final void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException { checkMode(opmode); // FIXME InvalidKeyException // if keysize exceeds the maximum allowable keysize // (jurisdiction policy files) spiImpl.engineInit(opmode, key, random); mode = opmode; } private void checkMode(int mode) { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE && mode != UNWRAP_MODE && mode != WRAP_MODE) { throw new InvalidParameterException("Invalid mode: " + mode); } } /** * Initializes this cipher instance with the specified key and algorithm * parameters. *

* The cipher is initialized for the specified operational mode (one of: * encryption, decryption, key wrapping or key unwrapping). *

* If this cipher instance needs any algorithm parameters and {@code params} * is {@code null}, the underlying implementation of this cipher is supposed * to generate the required parameters (using its provider or random * values). *

* When a cipher instance is initialized by a call to any of the {@code * init} methods, the state of the instance is overridden, means it is * equivalent to creating a new instance and calling it {@code init} method. * * @param opmode * the operation this cipher instance should be initialized for * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code * WRAP_MODE} or {@code UNWRAP_MODE}). * @param key * the input key for the operation. * @param params * the algorithm parameters. * @throws InvalidKeyException * if the specified key can not be used to initialize this * cipher instance. * @throws InvalidAlgorithmParameterException * it the specified parameters are inappropriate for this * cipher. */ public final void init(int opmode, Key key, AlgorithmParameterSpec params) throws InvalidKeyException, InvalidAlgorithmParameterException { if (secureRandom == null) { secureRandom = new SecureRandom(); } init(opmode, key, params, secureRandom); } /** * Initializes this cipher instance with the specified key, algorithm * parameters and a source of randomness. *

* The cipher is initialized for the specified operational mode (one of: * encryption, decryption, key wrapping or key unwrapping) depending on * {@code opmode}. *

* If this cipher instance needs any algorithm parameters and {@code params} * is {@code null}, the underlying implementation of this cipher is supposed * to generate the required parameters (using its provider or random * values). Random values are generated using {@code random}; *

* When a cipher instance is initialized by a call to any of the {@code * init} methods, the state of the instance is overridden, meaning that it * is equivalent to creating a new instance and calling it {@code init} * method. * * @param opmode * the operation this cipher instance should be initialized for * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code * WRAP_MODE} or {@code UNWRAP_MODE}). * @param key * the input key for the operation. * @param params * the algorithm parameters. * @param random * the source of randomness to use. * @throws InvalidKeyException * if the specified key can not be used to initialize this * cipher instance. * @throws InvalidAlgorithmParameterException * it the specified parameters are inappropriate for this * cipher. * @throws InvalidParameterException * if the specified {@code opmode} is invalid. */ public final void init(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { checkMode(opmode); // FIXME InvalidKeyException // if keysize exceeds the maximum allowable keysize // (jurisdiction policy files) // FIXME InvalidAlgorithmParameterException // cryptographic strength exceed the legal limits // (jurisdiction policy files) spiImpl.engineInit(opmode, key, params, random); mode = opmode; } /** * Initializes this cipher instance with the specified key and algorithm * parameters. *

* The cipher is initialized for the specified operation (one of: * encryption, decryption, key wrapping or key unwrapping) depending on * {@code opmode}. *

* If this cipher instance needs any algorithm parameters and {@code params} * is {@code null}, the underlying implementation of this cipher is supposed * to generate the required parameters (using its provider or random * values). *

* When a cipher instance is initialized by a call to any of the {@code * init} methods, the state of the instance is overridden, meaning that it * is equivalent to creating a new instance and calling it {@code init} * method. * * @param opmode * the operation this cipher instance should be initialized for * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code * WRAP_MODE} or {@code UNWRAP_MODE}). * @param key * the input key for the operation. * @param params * the algorithm parameters. * @throws InvalidKeyException * if the specified key can not be used to initialize this * cipher instance. * @throws InvalidAlgorithmParameterException * it the specified parameters are inappropriate for this * cipher. */ public final void init(int opmode, Key key, AlgorithmParameters params) throws InvalidKeyException, InvalidAlgorithmParameterException { if (secureRandom == null) { secureRandom = new SecureRandom(); } init(opmode, key, params, secureRandom); } /** * Initializes this cipher instance with the specified key, algorithm * parameters and a source of randomness. *

* The cipher will be initialized for the specified operation (one of: * encryption, decryption, key wrapping or key unwrapping) depending on * {@code opmode}. *

* If this cipher instance needs any algorithm parameters and {@code params} * is {@code null}, the underlying implementation of this cipher is supposed * to generate the required parameters (using its provider or random * values). Random values are generated using {@code random}. *

* When a cipher instance is initialized by a call to any of the {@code * init} methods, the state of the instance is overridden, means it is * equivalent to creating a new instance and calling it {@code init} method. * * @param opmode * the operation this cipher instance should be initialized for * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code * WRAP_MODE} or {@code UNWRAP_MODE}). * @param key * the input key for the operation. * @param params * the algorithm parameters. * @param random * the source of randomness to use. * @throws InvalidKeyException * if the specified key can not be used to initialize this * cipher instance. * @throws InvalidAlgorithmParameterException * if the specified parameters are inappropriate for this * cipher. * @throws InvalidParameterException * if the specified {@code opmode} is invalid. */ public final void init(int opmode, Key key, AlgorithmParameters params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { checkMode(opmode); // FIXME InvalidKeyException // if keysize exceeds the maximum allowable keysize // (jurisdiction policy files) // FIXME InvalidAlgorithmParameterException // cryptographic strength exceed the legal limits // (jurisdiction policy files) spiImpl.engineInit(opmode, key, params, random); mode = opmode; } /** * Initializes this cipher instance with the public key from the specified * certificate. *

* The cipher will be initialized for the specified operation (one of: * encryption, decryption, key wrapping or key unwrapping) depending on * {@code opmode}. *

* It the type of the certificate is X.509 and the certificate has a key * usage extension field marked as critical, the specified {@code * opmode} has the be enabled for this key, otherwise an {@code * InvalidKeyException} is thrown. *

* If this cipher instance needs any algorithm parameters that the key in * the certificate can not provide, the underlying implementation of this * cipher is supposed to generate the required parameters (using its * provider or random values). *

* When a cipher instance is initialized by a call to any of the {@code * init} methods, the state of the instance is overridden, means it is * equivalent to creating a new instance and calling it {@code init} method. * * @param opmode * the operation this cipher instance should be initialized for * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code * WRAP_MODE} or {@code UNWRAP_MODE}). * @param certificate * the certificate. * @throws InvalidKeyException * if the public key in the certificate can not be used to * initialize this cipher instance. */ public final void init(int opmode, Certificate certificate) throws InvalidKeyException { if (secureRandom == null) { secureRandom = new SecureRandom(); } init(opmode, certificate, secureRandom); } /** * Initializes this cipher instance with the public key from the specified * certificate and a source of randomness. *

* The cipher will be initialized for the specified operation (one of: * encryption, decryption, key wrapping or key unwrapping) depending on * {@code opmode}. *

* It the type of the certificate is X.509 and the certificate has a key * usage extension field marked as critical, the specified {@code * opmode} has the be enabled for this key, otherwise an {@code * InvalidKeyException} is thrown. *

* If this cipher instance needs any algorithm parameters that the key in * the certificate can not provide, the underlying implementation of this * cipher is supposed to generate the required parameters (using its * provider or random values). Random values are generated using {@code * random}. *

* When a cipher instance is initialized by a call to any of the {@code * init} methods, the state of the instance is overridden, means it is * equivalent to creating a new instance and calling it {@code init} method. * * @param opmode * the operation this cipher instance should be initialized for * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code * WRAP_MODE} or {@code UNWRAP_MODE}). * @param certificate * the certificate. * @param random * the source of randomness to be used. * @throws InvalidKeyException * if the public key in the certificate can not be used to * initialize this cipher instance. */ public final void init(int opmode, Certificate certificate, SecureRandom random) throws InvalidKeyException { checkMode(opmode); if (certificate instanceof X509Certificate) { Set ce = ((X509Certificate) certificate).getCriticalExtensionOIDs(); boolean critical = false; if (ce != null && !ce.isEmpty()) { for (String oid : ce) { if (oid.equals("2.5.29.15")) { // KeyUsage OID = 2.5.29.15 critical = true; break; } } if (critical) { boolean[] keyUsage = ((X509Certificate) certificate).getKeyUsage(); // As specified in RFC 3280: // Internet X.509 Public Key Infrastructure // Certificate and Certificate Revocation List (CRL) Profile. // Section 4.2.1.3 Key Usage // http://www.ietf.org/rfc/rfc3280.txt // // KeyUsage ::= BIT STRING {digitalSignature (0), // nonRepudiation (1), // keyEncipherment (2), // dataEncipherment (3), // keyAgreement (4), // keyCertSign (5), // cRLSign (6), // encipherOnly (7), // decipherOnly (8) } if (keyUsage != null) { if (opmode == ENCRYPT_MODE && !keyUsage[3]) { throw new InvalidKeyException("The public key in the certificate " + "cannot be used for ENCRYPT_MODE"); } else if (opmode == WRAP_MODE && !keyUsage[2]) { throw new InvalidKeyException("The public key in the certificate " + "cannot be used for WRAP_MODE"); } } } } } // FIXME InvalidKeyException // if keysize exceeds the maximum allowable keysize // (jurisdiction policy files) spiImpl.engineInit(opmode, certificate.getPublicKey(), random); mode = opmode; } /** * Continues a multi-part transformation (encryption or decryption). The * transformed bytes are returned. * * @param input * the input bytes to transform. * @return the transformed bytes in a new buffer, or {@code null} if the * input has zero length. * @throws IllegalStateException * if this cipher instance is not initialized for encryption or * decryption. * @throws IllegalArgumentException * if the input is {@code null}. */ public final byte[] update(byte[] input) { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { throw new IllegalStateException(); } if (input == null) { throw new IllegalArgumentException("input == null"); } if (input.length == 0) { return null; } return spiImpl.engineUpdate(input, 0, input.length); } /** * Continues a multi-part transformation (encryption or decryption). The * transformed bytes are returned. * * @param input * the input bytes to transform. * @param inputOffset * the offset in the input to start. * @param inputLen * the length of the input to transform. * @return the transformed bytes in a new buffer, or {@code null} if the * input has zero length. * @throws IllegalStateException * if this cipher instance is not initialized for encryption or * decryption. * @throws IllegalArgumentException * if the input is {@code null}, or if {@code inputOffset} and * {@code inputLen} do not specify a valid chunk in the input * buffer. */ public final byte[] update(byte[] input, int inputOffset, int inputLen) { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { throw new IllegalStateException(); } if (input == null) { throw new IllegalArgumentException("input == null"); } checkInputOffsetAndCount(input.length, inputOffset, inputLen); if (input.length == 0) { return null; } return spiImpl.engineUpdate(input, inputOffset, inputLen); } private static void checkInputOffsetAndCount(int inputArrayLength, int inputOffset, int inputLen) { if ((inputOffset | inputLen) < 0 || inputOffset > inputArrayLength || inputArrayLength - inputOffset < inputLen) { throw new IllegalArgumentException("input.length=" + inputArrayLength + "; inputOffset=" + inputOffset + "; inputLen=" + inputLen); } } /** * Continues a multi-part transformation (encryption or decryption). The * transformed bytes are stored in the {@code output} buffer. *

* If the size of the {@code output} buffer is too small to hold the result, * a {@code ShortBufferException} is thrown. Use * {@link Cipher#getOutputSize getOutputSize} to check for the size of the * output buffer. * * @param input * the input bytes to transform. * @param inputOffset * the offset in the input to start. * @param inputLen * the length of the input to transform. * @param output * the output buffer. * @return the number of bytes placed in output. * @throws ShortBufferException * if the size of the {@code output} buffer is too small. * @throws IllegalStateException * if this cipher instance is not initialized for encryption or * decryption. * @throws IllegalArgumentException * if the input is {@code null}, the output is {@code null}, or * if {@code inputOffset} and {@code inputLen} do not specify a * valid chunk in the input buffer. */ public final int update(byte[] input, int inputOffset, int inputLen, byte[] output) throws ShortBufferException { return update(input, inputOffset, inputLen, output, 0); } /** * Continues a multi-part transformation (encryption or decryption). The * transformed bytes are stored in the {@code output} buffer. *

* If the size of the {@code output} buffer is too small to hold the result, * a {@code ShortBufferException} is thrown. Use * {@link Cipher#getOutputSize getOutputSize} to check for the size of the * output buffer. * * @param input * the input bytes to transform. * @param inputOffset * the offset in the input to start. * @param inputLen * the length of the input to transform. * @param output * the output buffer. * @param outputOffset * the offset in the output buffer. * @return the number of bytes placed in output. * @throws ShortBufferException * if the size of the {@code output} buffer is too small. * @throws IllegalStateException * if this cipher instance is not initialized for encryption or * decryption. * @throws IllegalArgumentException * if the input is {@code null}, the output is {@code null}, or * if {@code inputOffset} and {@code inputLen} do not specify a * valid chunk in the input buffer. */ public final int update(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { throw new IllegalStateException(); } if (input == null) { throw new IllegalArgumentException("input == null"); } if (output == null) { throw new IllegalArgumentException("output == null"); } if (outputOffset < 0) { throw new IllegalArgumentException("outputOffset < 0. outputOffset=" + outputOffset); } checkInputOffsetAndCount(input.length, inputOffset, inputLen); if (input.length == 0) { return 0; } return spiImpl.engineUpdate(input, inputOffset, inputLen, output, outputOffset); } /** * Continues a multi-part transformation (encryption or decryption). The * {@code input.remaining()} bytes starting at {@code input.position()} are * transformed and stored in the {@code output} buffer. *

* If the {@code output.remaining()} is too small to hold the transformed * bytes a {@code ShortBufferException} is thrown. Use * {@link Cipher#getOutputSize getOutputSize} to check for the size of the * output buffer. * * @param input * the input buffer to transform. * @param output * the output buffer to store the result within. * @return the number of bytes stored in the output buffer. * @throws ShortBufferException * if the size of the {@code output} buffer is too small. * @throws IllegalStateException * if this cipher instance is not initialized for encryption or * decryption. * @throws IllegalArgumentException * if the input buffer and the output buffer are the identical * object. */ public final int update(ByteBuffer input, ByteBuffer output) throws ShortBufferException { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { throw new IllegalStateException(); } if (input == output) { throw new IllegalArgumentException("input == output"); } return spiImpl.engineUpdate(input, output); } /** * Finishes a multi-part transformation (encryption or decryption). *

* Processes any bytes that may have been buffered in previous {@code * update} calls. * * @return the final bytes from the transformation. * @throws IllegalBlockSizeException * if the size of the resulting bytes is not a multiple of the * cipher block size. * @throws BadPaddingException * if the padding of the data does not match the padding scheme. * @throws IllegalStateException * if this cipher instance is not initialized for encryption or * decryption. */ public final byte[] doFinal() throws IllegalBlockSizeException, BadPaddingException { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { throw new IllegalStateException(); } return spiImpl.engineDoFinal(null, 0, 0); } /** * Finishes a multi-part transformation (encryption or decryption). *

* Processes any bytes that may have been buffered in previous {@code * update} calls. *

* The final transformed bytes are stored in the {@code output} buffer. * * @param output * the output buffer. * @param outputOffset * the offset in the output buffer. * @return the number of bytes placed in the output buffer. * @throws IllegalBlockSizeException * if the size of the resulting bytes is not a multiple of the * cipher block size. * @throws ShortBufferException * if the size of the {@code output} buffer is too small. * @throws BadPaddingException * if the padding of the data does not match the padding scheme. * @throws IllegalStateException * if this cipher instance is not initialized for encryption or * decryption. */ public final int doFinal(byte[] output, int outputOffset) throws IllegalBlockSizeException, ShortBufferException, BadPaddingException { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { throw new IllegalStateException(); } if (outputOffset < 0) { throw new IllegalArgumentException("outputOffset < 0. outputOffset=" + outputOffset); } return spiImpl.engineDoFinal(null, 0, 0, output, outputOffset); } /** * Finishes a multi-part transformation (encryption or decryption). *

* Processes the bytes in {@code input} buffer, and any bytes that have been * buffered in previous {@code update} calls. * * @param input * the input buffer. * @return the final bytes from the transformation. * @throws IllegalBlockSizeException * if the size of the resulting bytes is not a multiple of the * cipher block size. * @throws BadPaddingException * if the padding of the data does not match the padding scheme. * @throws IllegalStateException * if this cipher instance is not initialized for encryption or * decryption. */ public final byte[] doFinal(byte[] input) throws IllegalBlockSizeException, BadPaddingException { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { throw new IllegalStateException(); } return spiImpl.engineDoFinal(input, 0, input.length); } /** * Finishes a multi-part transformation (encryption or decryption). *

* Processes the {@code inputLen} bytes in {@code input} buffer at {@code * inputOffset}, and any bytes that have been buffered in previous {@code * update} calls. * * @param input * the input buffer. * @param inputOffset * the offset in the input buffer. * @param inputLen * the length of the input * @return the final bytes from the transformation. * @throws IllegalBlockSizeException * if the size of the resulting bytes is not a multiple of the * cipher block size. * @throws BadPaddingException * if the padding of the data does not match the padding scheme. * @throws IllegalStateException * if this cipher instance is not initialized for encryption or * decryption. * @throws IllegalArgumentException * if {@code inputOffset} and {@code inputLen} do not specify an * valid chunk in the input buffer. */ public final byte[] doFinal(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { throw new IllegalStateException(); } checkInputOffsetAndCount(input.length, inputOffset, inputLen); return spiImpl.engineDoFinal(input, inputOffset, inputLen); } /** * Finishes a multi-part transformation (encryption or decryption). *

* Processes the {@code inputLen} bytes in {@code input} buffer at {@code * inputOffset}, and any bytes that have been buffered in previous {@code * update} calls. * * @param input * the input buffer. * @param inputOffset * the offset in the input buffer. * @param inputLen * the length of the input. * @param output * the output buffer for the transformed bytes. * @return the number of bytes placed in the output buffer. * @throws ShortBufferException * if the size of the {@code output} buffer is too small. * @throws IllegalBlockSizeException * if the size of the resulting bytes is not a multiple of the * cipher block size. * @throws BadPaddingException * if the padding of the data does not match the padding scheme. * @throws IllegalStateException * if this cipher instance is not initialized for encryption or * decryption. * @throws IllegalArgumentException * if {@code inputOffset} and {@code inputLen} do not specify an * valid chunk in the input buffer. */ public final int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { return doFinal(input, inputOffset, inputLen, output, 0); } /** * Finishes a multi-part transformation (encryption or decryption). *

* Processes the {@code inputLen} bytes in {@code input} buffer at {@code * inputOffset}, and any bytes that have been buffered in previous {@code * update} calls. * * @param input * the input buffer. * @param inputOffset * the offset in the input buffer. * @param inputLen * the length of the input. * @param output * the output buffer for the transformed bytes. * @param outputOffset * the offset in the output buffer. * @return the number of bytes placed in the output buffer. * @throws ShortBufferException * if the size of the {@code output} buffer is too small. * @throws IllegalBlockSizeException * if the size of the resulting bytes is not a multiple of the * cipher block size. * @throws BadPaddingException * if the padding of the data does not match the padding scheme. * @throws IllegalStateException * if this cipher instance is not initialized for encryption or * decryption. * @throws IllegalArgumentException * if {@code inputOffset} and {@code inputLen} do not specify an * valid chunk in the input buffer. */ public final int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { throw new IllegalStateException(); } checkInputOffsetAndCount(input.length, inputOffset, inputLen); return spiImpl.engineDoFinal(input, inputOffset, inputLen, output, outputOffset); } /** * Finishes a multi-part transformation (encryption or decryption). *

* Processes the {@code input.remaining()} bytes in {@code input} buffer at * {@code input.position()}, and any bytes that have been buffered in * previous {@code update} calls. The transformed bytes are placed into * {@code output} buffer. * * @param input * the input buffer. * @param output * the output buffer. * @return the number of bytes placed into the output buffer. * @throws ShortBufferException * if the size of the {@code output} buffer is too small. * @throws IllegalBlockSizeException * if the size of the resulting bytes is not a multiple of the * cipher block size. * @throws BadPaddingException * if the padding of the data does not match the padding scheme. * @throws IllegalArgumentException * if the input buffer and the output buffer are the same * object. * @throws IllegalStateException * if this cipher instance is not initialized for encryption or * decryption. */ public final int doFinal(ByteBuffer input, ByteBuffer output) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { throw new IllegalStateException(); } if (input == output) { throw new IllegalArgumentException("input == output"); } return spiImpl.engineDoFinal(input, output); } /** * Wraps a key using this cipher instance. * * @param key * the key to wrap. * @return the wrapped key. * @throws IllegalBlockSizeException * if the size of the resulting bytes is not a multiple of the * cipher block size. * @throws InvalidKeyException * if this cipher instance can not wrap this key. * @throws IllegalStateException * if this cipher instance is not initialized for wrapping. */ public final byte[] wrap(Key key) throws IllegalBlockSizeException, InvalidKeyException { if (mode != WRAP_MODE) { throw new IllegalStateException(); } return spiImpl.engineWrap(key); } /** * Unwraps a key using this cipher instance. * * @param wrappedKey * the wrapped key to unwrap. * @param wrappedKeyAlgorithm * the algorithm for the wrapped key. * @param wrappedKeyType * the type of the wrapped key (one of: {@code SECRET_KEY * , PRIVATE_KEY} or {@code PUBLIC_KEY}) * @return the unwrapped key * @throws InvalidKeyException * if the {@code wrappedKey} can not be unwrapped to a key of * type {@code wrappedKeyType} for the {@code * wrappedKeyAlgorithm}. * @throws NoSuchAlgorithmException * if no provider can be found that can create a key of type * {@code wrappedKeyType} for the {@code wrappedKeyAlgorithm}. * @throws IllegalStateException * if this cipher instance is not initialized for unwrapping. */ public final Key unwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType) throws InvalidKeyException, NoSuchAlgorithmException { if (mode != UNWRAP_MODE) { throw new IllegalStateException(); } return spiImpl.engineUnwrap(wrappedKey, wrappedKeyAlgorithm, wrappedKeyType); } /** * Returns the maximum key length for the specified transformation. * * @param transformation * the transformation name. * @return the maximum key length, currently {@code Integer.MAX_VALUE}. * @throws NoSuchAlgorithmException * if no provider for the specified {@code transformation} can * be found. * @throws NullPointerException * if {@code transformation} is {@code null}. */ public static final int getMaxAllowedKeyLength(String transformation) throws NoSuchAlgorithmException { if (transformation == null) { throw new NullPointerException("transformation == null"); } checkTransformation(transformation); //FIXME jurisdiction policy files return Integer.MAX_VALUE; } /** * Returns the maximum cipher parameter value for the specified * transformation. If there is no maximum limit, {@code null} is returned. * * @param transformation * the transformation name. * @return a parameter spec holding the maximum value or {@code null}. * Currently {@code null}. * @throws NoSuchAlgorithmException * if no provider for the specified {@code transformation} can * be found. * @throws NullPointerException * if {@code transformation} is {@code null}. */ public static final AlgorithmParameterSpec getMaxAllowedParameterSpec( String transformation) throws NoSuchAlgorithmException { if (transformation == null) { throw new NullPointerException("transformation == null"); } checkTransformation(transformation); //FIXME jurisdiction policy files return null; } }