| /* |
| * 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.Provider.Service; |
| import java.security.ProviderException; |
| 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.ArrayList; |
| import java.util.Locale; |
| 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: |
| * <ul> |
| * <li><i>"algorithm/mode/padding"</i></li> or |
| * <li><i>"algorithm"</i></li> |
| * </ul> |
| * <i>algorithm</i> is the name of a cryptographic algorithm, <i>mode</i> is the |
| * name of a feedback mode and <i>padding</i> is the name of a padding scheme. |
| * If <i>mode</i> and/or <i>padding</i> values are omitted, provider specific |
| * default values will be used. |
| * <p> |
| * A valid transformation would be: |
| * <ul> |
| * {@code Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");} |
| * </ul> |
| * When a block cipher is requested 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. <i>"AES/CFB8/NoPadding"</i>. 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; |
| |
| /** Items that need to be set on the Cipher instance. */ |
| private enum NeedToSet { |
| NONE, MODE, PADDING, BOTH, |
| }; |
| |
| /** |
| * Used to keep track of which underlying {@code CipherSpi#engineInit(...)} |
| * variant to call when testing suitability. |
| */ |
| private static enum InitType { |
| KEY, ALGORITHM_PARAMS, ALGORITHM_PARAM_SPEC, |
| }; |
| |
| /** |
| * Keeps track of the possible arguments to {@code Cipher#init(...)}. |
| */ |
| private static class InitParams { |
| private final InitType initType; |
| private final int opmode; |
| private final Key key; |
| private final SecureRandom random; |
| private final AlgorithmParameterSpec spec; |
| private final AlgorithmParameters params; |
| |
| private InitParams(InitType initType, int opmode, Key key, SecureRandom random, |
| AlgorithmParameterSpec spec, AlgorithmParameters params) { |
| this.initType = initType; |
| this.opmode = opmode; |
| this.key = key; |
| this.random = random; |
| this.spec = spec; |
| this.params = params; |
| } |
| } |
| |
| /** |
| * Expresses the various types of transforms that may be used during |
| * initialization. |
| */ |
| private static class Transform { |
| private final String name; |
| private final NeedToSet needToSet; |
| |
| public Transform(String name, NeedToSet needToSet) { |
| this.name = name; |
| this.needToSet = needToSet; |
| } |
| } |
| |
| /** |
| * The service name. |
| */ |
| private static final String SERVICE = "Cipher"; |
| |
| /** |
| * Used to access common engine functionality. |
| */ |
| private static final Engine ENGINE = new Engine(SERVICE); |
| |
| /** The attribute used for supported paddings. */ |
| private static final String ATTRIBUTE_PADDINGS = "SupportedPaddings"; |
| |
| /** The attribute used for supported modes. */ |
| private static final String ATTRIBUTE_MODES = "SupportedModes"; |
| |
| /** |
| * The provider. |
| */ |
| private Provider provider; |
| |
| /** |
| * The provider specified when instance created. |
| */ |
| private final Provider specifiedProvider; |
| |
| /** |
| * The SPI implementation. |
| */ |
| private CipherSpi spiImpl; |
| |
| /** |
| * The SPI implementation. |
| */ |
| private final CipherSpi specifiedSpi; |
| |
| /** |
| * The transformation. |
| */ |
| private final String transformation; |
| |
| /** |
| * The transformation split into parts. |
| */ |
| private final String[] transformParts; |
| |
| /** |
| * Lock held while the SPI is initializing. |
| */ |
| private final Object initLock = new Object(); |
| |
| 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.specifiedProvider = provider; |
| this.specifiedSpi = cipherSpi; |
| this.transformation = transformation; |
| this.transformParts = null; |
| } |
| |
| private Cipher(String transformation, String[] transformParts, Provider provider) { |
| this.transformation = transformation; |
| this.transformParts = transformParts; |
| this.specifiedProvider = provider; |
| this.specifiedSpi = null; |
| } |
| |
| |
| /** |
| * 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 |
| * <i>transformation</i>, or it is {@code null}, empty or in an |
| * invalid format. |
| * @throws NoSuchPaddingException |
| * if no installed provider can provide the padding scheme in |
| * the <i>transformation</i>. |
| */ |
| 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 |
| * <i>transformation</i>, 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 <i>transformation</i> |
| * 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. The |
| * {@code provider} supplied does not have to be registered. |
| * |
| * @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 |
| * <i>transformation</i>, or it is {@code null}, empty or in an |
| * invalid format. |
| * @throws NoSuchPaddingException |
| * if the requested padding scheme in the <i>transformation</i> |
| * 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"); |
| } |
| return getCipher(transformation, provider); |
| } |
| |
| private static NoSuchAlgorithmException invalidTransformation(String transformation) |
| throws NoSuchAlgorithmException { |
| throw new NoSuchAlgorithmException("Invalid transformation: " + transformation); |
| } |
| |
| /** |
| * Create a Cipher instance but don't choose a CipherSpi until we have more |
| * information. |
| */ |
| private static Cipher getCipher(String transformation, Provider provider) |
| throws NoSuchAlgorithmException, NoSuchPaddingException { |
| if (transformation == null || transformation.isEmpty()) { |
| throw invalidTransformation(transformation); |
| } |
| |
| String[] transformParts = checkTransformation(transformation); |
| |
| Engine.SpiAndProvider sap; |
| try { |
| sap = tryCombinations(null /* params */, provider, transformation, transformParts); |
| } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { |
| // should never happen since we passed in null params |
| throw new ProviderException(e); |
| } |
| |
| if (sap == null) { |
| if (provider == null) { |
| throw new NoSuchAlgorithmException("No provider found for " + transformation); |
| } else { |
| throw new NoSuchAlgorithmException("Provider " + provider.getName() |
| + " does not provide " + transformation); |
| } |
| } |
| return new Cipher(transformation, transformParts, provider); |
| } |
| |
| /** |
| * Checks that the provided algorithm {@code transformation} string is a |
| * valid input. The algorithm is the only mandatory field and input can be |
| * of the form: |
| * <ul> |
| * <li><code>"[cipher]"</code> |
| * <li><code>"[cipher]/[mode]/[padding]"</code> |
| * <li><code>"[cipher]//[padding]"</code> |
| * <li><code>"[cipher]/[mode]"</code> |
| * </ul> |
| * <p> |
| * Returns the specified transformation split up into three parts |
| * corresponding to their function: |
| * <p> |
| * <code> |
| * {<algorithm>, <mode>, <padding>} |
| * </code> |
| * <p> |
| */ |
| private static String[] checkTransformation(String transformation) |
| throws NoSuchAlgorithmException { |
| // ignore an extra prefix / characters such as in |
| // "/DES/CBC/PKCS5Padding" 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; |
| } |
| |
| /** |
| * Makes sure a CipherSpi that matches this type is selected. If |
| * {@code key != null} then it assumes that a suitable provider exists for |
| * this instance (used by {@link #init}. If the {@code initParams} is passed |
| * in, then the {@code CipherSpi} returned will be initialized. |
| * |
| * @throws InvalidKeyException if the specified key cannot be used to |
| * initialize this cipher. |
| * @throws InvalidAlgorithmParameterException |
| */ |
| private CipherSpi getSpi(InitParams initParams) throws InvalidKeyException, |
| InvalidAlgorithmParameterException { |
| if (specifiedSpi != null) { |
| return specifiedSpi; |
| } |
| |
| synchronized (initLock) { |
| // This is not only a matter of performance. Many methods like update, doFinal, etc. |
| // call {@code #getSpi()} (ie, {@code #getSpi(null /* params */)}) and without this |
| // shortcut they would override an spi that was chosen using the key. |
| if (spiImpl != null && initParams == null) { |
| return spiImpl; |
| } |
| |
| final Engine.SpiAndProvider sap = tryCombinations(initParams, specifiedProvider, |
| transformation, transformParts); |
| if (sap == null) { |
| throw new ProviderException("No provider found for " + transformation); |
| } |
| |
| spiImpl = (CipherSpi) sap.spi; |
| provider = sap.provider; |
| |
| return spiImpl; |
| } |
| } |
| |
| /** |
| * Convenience call when the Key is not available. |
| */ |
| private CipherSpi getSpi() { |
| try { |
| return getSpi(null); |
| } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { |
| throw new ProviderException("Exception thrown when params == null", e); |
| } |
| } |
| |
| /** |
| * Returns the {@code CipherSpi} backing this {@code Cipher} or {@code null} if no |
| * {@code CipherSpi} is backing this {@code Cipher}. |
| * |
| * @hide |
| */ |
| public CipherSpi getCurrentSpi() { |
| if (specifiedSpi != null) { |
| return specifiedSpi; |
| } |
| |
| synchronized (initLock) { |
| return spiImpl; |
| } |
| } |
| |
| /** |
| * Tries to find the correct {@code Cipher} transform to use. Returns a |
| * {@link Engine.SpiAndProvider}, throws the first exception that was |
| * encountered during attempted initialization, or {@code null} if there are |
| * no providers that support the {@code initParams}. |
| * <p> |
| * {@code transformParts} must be in the format returned by |
| * {@link #checkTransformation(String)}. The combinations of mode strings |
| * tried are as follows: |
| * <ul> |
| * <li><code>[cipher]/[mode]/[padding]</code> |
| * <li><code>[cipher]/[mode]</code> |
| * <li><code>[cipher]//[padding]</code> |
| * <li><code>[cipher]</code> |
| * </ul> |
| */ |
| private static Engine.SpiAndProvider tryCombinations(InitParams initParams, Provider provider, |
| String transformation, String[] transformParts) throws InvalidKeyException, |
| InvalidAlgorithmParameterException { |
| // Enumerate all the transforms we need to try |
| ArrayList<Transform> transforms = new ArrayList<Transform>(); |
| if (transformParts[1] != null && transformParts[2] != null) { |
| transforms.add(new Transform(transformParts[0] + "/" + transformParts[1] + "/" |
| + transformParts[2], NeedToSet.NONE)); |
| } |
| if (transformParts[1] != null) { |
| transforms.add(new Transform(transformParts[0] + "/" + transformParts[1], |
| NeedToSet.PADDING)); |
| } |
| if (transformParts[2] != null) { |
| transforms.add(new Transform(transformParts[0] + "//" + transformParts[2], |
| NeedToSet.MODE)); |
| } |
| transforms.add(new Transform(transformParts[0], NeedToSet.BOTH)); |
| |
| // Try each of the transforms and keep track of the first exception |
| // encountered. |
| Exception cause = null; |
| for (Transform transform : transforms) { |
| if (provider != null) { |
| Provider.Service service = provider.getService(SERVICE, transform.name); |
| if (service == null) { |
| continue; |
| } |
| return tryTransformWithProvider(initParams, transformParts, transform.needToSet, |
| service); |
| } |
| ArrayList<Provider.Service> services = ENGINE.getServices(transform.name); |
| if (services == null || services.isEmpty()) { |
| continue; |
| } |
| for (Provider.Service service : services) { |
| if (initParams == null || initParams.key == null |
| || service.supportsParameter(initParams.key)) { |
| try { |
| Engine.SpiAndProvider sap = tryTransformWithProvider(initParams, |
| transformParts, transform.needToSet, service); |
| if (sap != null) { |
| return sap; |
| } |
| } catch (Exception e) { |
| if (cause == null) { |
| cause = e; |
| } |
| } |
| } |
| } |
| } |
| if (cause instanceof InvalidKeyException) { |
| throw (InvalidKeyException) cause; |
| } else if (cause instanceof InvalidAlgorithmParameterException) { |
| throw (InvalidAlgorithmParameterException) cause; |
| } else if (cause instanceof RuntimeException) { |
| throw (RuntimeException) cause; |
| } else if (cause != null) { |
| throw new InvalidKeyException("No provider can be initialized with given key", cause); |
| } else if (initParams == null || initParams.key == null) { |
| return null; |
| } else { |
| // Since the key is not null, a suitable provider exists, |
| // and it is an InvalidKeyException. |
| throw new InvalidKeyException("No provider offers " + transformation + " for " |
| + initParams.key.getAlgorithm() + " key of class " |
| + initParams.key.getClass().getName() + " and export format " |
| + initParams.key.getFormat()); |
| } |
| } |
| |
| /** |
| * Tries to initialize the {@code Cipher} from a given {@code service}. If |
| * initialization is successful, the initialized {@code spi} is returned. If |
| * the {@code service} cannot be initialized with the specified |
| * {@code initParams}, then it's expected to throw |
| * {@code InvalidKeyException} or {@code InvalidAlgorithmParameterException} |
| * as a hint to the caller that it should continue searching for a |
| * {@code Service} that will work. |
| */ |
| private static Engine.SpiAndProvider tryTransformWithProvider(InitParams initParams, |
| String[] transformParts, NeedToSet type, Provider.Service service) |
| throws InvalidKeyException, InvalidAlgorithmParameterException { |
| try { |
| /* |
| * Check to see if the Cipher even supports the attributes before |
| * trying to instantiate it. |
| */ |
| if (!matchAttribute(service, ATTRIBUTE_MODES, transformParts[1]) |
| || !matchAttribute(service, ATTRIBUTE_PADDINGS, transformParts[2])) { |
| return null; |
| } |
| |
| Engine.SpiAndProvider sap = ENGINE.getInstance(service, null); |
| if (sap.spi == null || sap.provider == null) { |
| return null; |
| } |
| CipherSpi spi = (CipherSpi) sap.spi; |
| if (((type == NeedToSet.MODE) || (type == NeedToSet.BOTH)) |
| && (transformParts[1] != null)) { |
| spi.engineSetMode(transformParts[1]); |
| } |
| if (((type == NeedToSet.PADDING) || (type == NeedToSet.BOTH)) |
| && (transformParts[2] != null)) { |
| spi.engineSetPadding(transformParts[2]); |
| } |
| |
| if (initParams != null) { |
| switch (initParams.initType) { |
| case ALGORITHM_PARAMS: |
| spi.engineInit(initParams.opmode, initParams.key, initParams.params, |
| initParams.random); |
| break; |
| case ALGORITHM_PARAM_SPEC: |
| spi.engineInit(initParams.opmode, initParams.key, initParams.spec, |
| initParams.random); |
| break; |
| case KEY: |
| spi.engineInit(initParams.opmode, initParams.key, initParams.random); |
| break; |
| default: |
| throw new AssertionError("This should never be reached"); |
| } |
| } |
| return sap; |
| } catch (NoSuchAlgorithmException ignored) { |
| } catch (NoSuchPaddingException ignored) { |
| } |
| return null; |
| } |
| |
| /** |
| * If the attribute listed exists, check that it matches the regular |
| * expression. |
| */ |
| private static boolean matchAttribute(Service service, String attr, String value) { |
| if (value == null) { |
| return true; |
| } |
| final String pattern = service.getAttribute(attr); |
| if (pattern == null) { |
| return true; |
| } |
| final String valueUc = value.toUpperCase(Locale.US); |
| return valueUc.matches(pattern.toUpperCase(Locale.US)); |
| } |
| |
| /** |
| * Returns the provider of this cipher instance. |
| * |
| * @return the provider of this cipher instance. |
| */ |
| public final Provider getProvider() { |
| getSpi(); |
| return provider; |
| } |
| |
| /** |
| * Returns the name of the algorithm of this cipher instance. |
| * <p> |
| * This is the name of the <i>transformation</i> 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 getSpi().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 getSpi().engineGetOutputSize(inputLen); |
| } |
| |
| /** |
| * Returns the <i>initialization vector</i> for this cipher instance. |
| * |
| * @return the <i>initialization vector</i> for this cipher instance. |
| */ |
| public final byte[] getIV() { |
| return getSpi().engineGetIV(); |
| } |
| |
| /** |
| * Returns the parameters that where used to create this cipher instance. |
| * <p> |
| * 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 getSpi().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; |
| // } |
| |
| } |
| |
| /** |
| * Checks that the provided {@code mode} is one that is valid for |
| * {@code Cipher}. |
| */ |
| 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. |
| * <p> |
| * The cipher is initialized for the specified operational mode (one of: |
| * encryption, decryption, key wrapping or key unwrapping) depending on |
| * {@code opmode}. |
| * <p> |
| * 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). |
| * <p> |
| * 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. |
| * <p> |
| * The cipher is initialized for the specified operational mode (one of: |
| * encryption, decryption, key wrapping or key unwrapping) depending on |
| * {@code opmode}. |
| * <p> |
| * 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}; |
| * <p> |
| * 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) |
| try { |
| getSpi(new InitParams(InitType.KEY, opmode, key, random, null, null)); |
| } catch (InvalidAlgorithmParameterException e) { |
| // Should never happen since we only specified the key. |
| throw new ProviderException("Invalid parameters when params == null", e); |
| } |
| mode = opmode; |
| } |
| |
| /** |
| * Initializes this cipher instance with the specified key and algorithm |
| * parameters. |
| * <p> |
| * The cipher is initialized for the specified operational mode (one of: |
| * encryption, decryption, key wrapping or key unwrapping). |
| * <p> |
| * 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). |
| * <p> |
| * 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. |
| * <p> |
| * The cipher is initialized for the specified operational mode (one of: |
| * encryption, decryption, key wrapping or key unwrapping) depending on |
| * {@code opmode}. |
| * <p> |
| * 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}; |
| * <p> |
| * 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) |
| getSpi(new InitParams(InitType.ALGORITHM_PARAM_SPEC, opmode, key, random, params, null)); |
| mode = opmode; |
| } |
| |
| /** |
| * Initializes this cipher instance with the specified key and algorithm |
| * parameters. |
| * <p> |
| * The cipher is initialized for the specified operation (one of: |
| * encryption, decryption, key wrapping or key unwrapping) depending on |
| * {@code opmode}. |
| * <p> |
| * 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). |
| * <p> |
| * 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. |
| * <p> |
| * The cipher will be initialized for the specified operation (one of: |
| * encryption, decryption, key wrapping or key unwrapping) depending on |
| * {@code opmode}. |
| * <p> |
| * 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}. |
| * <p> |
| * 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) |
| getSpi(new InitParams(InitType.ALGORITHM_PARAMS, opmode, key, random, null, params)); |
| mode = opmode; |
| } |
| |
| /** |
| * Initializes this cipher instance with the public key from the specified |
| * certificate. |
| * <p> |
| * The cipher will be initialized for the specified operation (one of: |
| * encryption, decryption, key wrapping or key unwrapping) depending on |
| * {@code opmode}. |
| * <p> |
| * It the type of the certificate is X.509 and the certificate has a <i>key |
| * usage</i> extension field marked as critical, the specified {@code |
| * opmode} has the be enabled for this key, otherwise an {@code |
| * InvalidKeyException} is thrown. |
| * <p> |
| * 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). |
| * <p> |
| * 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. |
| * <p> |
| * The cipher will be initialized for the specified operation (one of: |
| * encryption, decryption, key wrapping or key unwrapping) depending on |
| * {@code opmode}. |
| * <p> |
| * It the type of the certificate is X.509 and the certificate has a <i>key |
| * usage</i> extension field marked as critical, the specified {@code |
| * opmode} has the be enabled for this key, otherwise an {@code |
| * InvalidKeyException} is thrown. |
| * <p> |
| * 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}. |
| * <p> |
| * 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<String> 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) |
| final Key key = certificate.getPublicKey(); |
| try { |
| getSpi(new InitParams(InitType.KEY, opmode, key, random, null, null)); |
| } catch (InvalidAlgorithmParameterException e) { |
| // Should never happen since we only specified the key. |
| throw new ProviderException("Invalid parameters when params == null", e); |
| } |
| 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 getSpi().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 {@code inputLen} is zero. |
| * @throws IllegalStateException |
| * if this cipher instance is not initialized for encryption or |
| * decryption. |
| * @throws IllegalArgumentException |
| * if {@code 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 (inputLen == 0) { |
| return null; |
| } |
| return getSpi().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. |
| * <p> |
| * 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. |
| * <p> |
| * 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 getSpi().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. |
| * <p> |
| * 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 getSpi().engineUpdate(input, output); |
| } |
| |
| /** |
| * Continues a multi-part transformation (encryption or decryption) with |
| * Authenticated Additional Data (AAD). AAD may only be added after the |
| * {@code Cipher} is initialized and before any data is passed to the |
| * instance. |
| * <p> |
| * This is only usable with cipher modes that support Authenticated |
| * Encryption with Additional Data (AEAD) such as Galois/Counter Mode (GCM). |
| * |
| * @param input bytes of AAD to use with the cipher |
| * @throws IllegalStateException |
| * if this cipher instance is not initialized for encryption or |
| * decryption. |
| * @throws IllegalArgumentException |
| * if {@code input} is {@code null} |
| * @throws UnsupportedOperationException if the cipher does not support AEAD |
| * @since 1.7 |
| */ |
| public final void updateAAD(byte[] input) { |
| if (input == null) { |
| throw new IllegalArgumentException("input == null"); |
| } |
| if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { |
| throw new IllegalStateException(); |
| } |
| if (input.length == 0) { |
| return; |
| } |
| getSpi().engineUpdateAAD(input, 0, input.length); |
| } |
| |
| /** |
| * Continues a multi-part transformation (encryption or decryption) with |
| * Authenticated Additional Data (AAD). AAD may only be added after the |
| * {@code Cipher} is initialized and before any data is passed to the |
| * instance. |
| * <p> |
| * This is only usable with cipher modes that support Authenticated |
| * Encryption with Additional Data (AEAD) such as Galois/Counter Mode (GCM). |
| * |
| * @param input bytes of AAD to use with the cipher |
| * @param inputOffset offset within bytes of additional data to add to cipher |
| * @param inputLen length of bytes of additional data to add to cipher |
| * @throws IllegalStateException |
| * if this cipher instance is not initialized for encryption or |
| * decryption. |
| * @throws IllegalArgumentException |
| * if {@code input} is {@code null}, or if {@code inputOffset} and |
| * {@code inputLen} do not specify a valid chunk in the input |
| * buffer. |
| * @throws UnsupportedOperationException if the cipher does not support AEAD |
| * @since 1.7 |
| */ |
| public final void updateAAD(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; |
| } |
| getSpi().engineUpdateAAD(input, inputOffset, inputLen); |
| } |
| |
| /** |
| * Continues a multi-part transformation (encryption or decryption) with |
| * Authenticated Additional Data (AAD). AAD may only be added after the |
| * {@code Cipher} is initialized and before any data is passed to the |
| * instance. |
| * <p> |
| * This is only usable with cipher modes that support Authenticated |
| * Encryption with Additional Data (AEAD) such as Galois/Counter Mode (GCM). |
| * |
| * @param input buffer of AAD to be used |
| * @throws IllegalStateException |
| * if this cipher instance is not initialized for encryption or |
| * decryption. |
| * @throws UnsupportedOperationException if the cipher does not support AEAD |
| * @since 1.7 |
| */ |
| public final void updateAAD(ByteBuffer input) { |
| if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { |
| throw new IllegalStateException("Cipher is not initialized"); |
| } |
| if (input == null) { |
| throw new IllegalArgumentException("input == null"); |
| } |
| getSpi().engineUpdateAAD(input); |
| } |
| |
| /** |
| * Finishes a multi-part transformation (encryption or decryption). |
| * <p> |
| * 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 getSpi().engineDoFinal(null, 0, 0); |
| } |
| |
| /** |
| * Finishes a multi-part transformation (encryption or decryption). |
| * <p> |
| * Processes any bytes that may have been buffered in previous {@code |
| * update} calls. |
| * <p> |
| * 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 getSpi().engineDoFinal(null, 0, 0, output, outputOffset); |
| } |
| |
| /** |
| * Finishes a multi-part transformation (encryption or decryption). |
| * <p> |
| * 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 getSpi().engineDoFinal(input, 0, input.length); |
| } |
| |
| /** |
| * Finishes a multi-part transformation (encryption or decryption). |
| * <p> |
| * 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 getSpi().engineDoFinal(input, inputOffset, inputLen); |
| } |
| |
| /** |
| * Finishes a multi-part transformation (encryption or decryption). |
| * <p> |
| * 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). |
| * <p> |
| * 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 getSpi().engineDoFinal(input, inputOffset, inputLen, output, |
| outputOffset); |
| } |
| |
| /** |
| * Finishes a multi-part transformation (encryption or decryption). |
| * <p> |
| * 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 getSpi().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 getSpi().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 |
| * <code>, <code>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 getSpi().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; |
| } |
| } |