| /* |
| * 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.Key; |
| import java.security.NoSuchAlgorithmException; |
| import java.security.SecureRandom; |
| import java.security.spec.AlgorithmParameterSpec; |
| |
| /** |
| * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) for |
| * cryptographic ciphers. |
| * <p> |
| * Implementers of cryptographic ciphers must implement all the abstract methods |
| * for every cipher they implement. {@code CipherSpi} instances are created |
| * along with ciphers when the {@link Cipher#getInstance} method is called. A |
| * {@code Cipher} is referenced by a <i>transformation</i>, which is a string |
| * that describes the operation (or set of operations), always consisting of the |
| * cipher's name and optionally followed by a mode and a padding, in the form: |
| * <ul> |
| * <li>"algorithm"</li>or |
| * <li>"algorithm/mode/padding"</li> |
| * </ul> |
| * The following behavior should be implemented for obtaining {@code Cipher} |
| * instances. |
| * <p> |
| * When one of the {@link Cipher#getInstance} factory methods is called with a |
| * <i>transformation</i> that is only an <i>algorithm</i>, check if the provider |
| * defines a {@code CipherSpi} for "algorithm", if so: return it, otherwise |
| * throw a {@link NoSuchAlgorithmException}. |
| * <p> |
| * The following rules apply when a <i>transformation</i> is of the form |
| * "algorithm/mode/padding": |
| * <ul> |
| * 1. The Provider has a {@code CipherSpi} subclass registered for |
| * "algorithm/mode/padding": return it, otherwise go to step 2. |
| * </ul> |
| * <ul> |
| * 2. The Provider has a {@code CipherSpi} subclass registered for |
| * "algorithm/mode": instantiate it, call |
| * {@link CipherSpi#engineSetPadding(String) engineSetPadding(String)} for the |
| * padding name and return it, otherwise go to step 3. |
| * </ul> |
| * <ul> |
| * 3. The Provider has a {@code CipherSpi} subclass registered for |
| * "algorithm//padding": instantiate it, call |
| * {@link CipherSpi#engineSetMode(String) engineSetMode(String)} for the mode |
| * name and return it, otherwise go to step 4. |
| * </ul> |
| * <ul> |
| * 4. The Provider has a {@code CipherSpi} subclass registered for "algorithm": |
| * instantiate it, call {@link CipherSpi#engineSetMode(String) |
| * engineSetMode(String)} for the mode name , call |
| * {@link CipherSpi#engineSetPadding(String) engineSetPadding(String)} for the |
| * padding name and return it, otherwise throw a |
| * {@link NoSuchAlgorithmException}. |
| * </ul> |
| * |
| * @see Cipher |
| */ |
| public abstract class CipherSpi { |
| |
| /** |
| * Creates a new {@code CipherSpi} instance. |
| */ |
| public CipherSpi() { |
| } |
| |
| /** |
| * Sets the mode for this cipher. |
| * |
| * @param mode |
| * the name of the cipher mode. |
| * @throws NoSuchAlgorithmException |
| * if the specified cipher mode is not supported by this |
| * provider. |
| */ |
| protected abstract void engineSetMode(String mode) |
| throws NoSuchAlgorithmException; |
| |
| /** |
| * Sets the padding method for this cipher. |
| * |
| * @param padding |
| * the name of the padding method. |
| * @throws NoSuchPaddingException |
| * if the specified padding method is not supported by this |
| * cipher. |
| */ |
| protected abstract void engineSetPadding(String padding) |
| throws NoSuchPaddingException; |
| |
| /** |
| * Returns the block size of this cipher (in bytes) |
| * |
| * @return the block size of this cipher, or zero if this cipher is not a |
| * block cipher. |
| */ |
| protected abstract int engineGetBlockSize(); |
| |
| /** |
| * Returns the size for a buffer (in bytes), that the next call to {@code |
| * update} of {@code doFinal} would return, taking into account any buffered |
| * data from previous {@code update} calls and padding. |
| * <p> |
| * The actual output length of the next call to {@code update} or {@code |
| * doFinal} may be smaller than the length returned by this method. |
| * |
| * @param inputLen |
| * the length of the input (in bytes). |
| * @return the size for a buffer (in bytes). |
| */ |
| protected abstract int engineGetOutputSize(int inputLen); |
| |
| /** |
| * Returns the Initialization Vector (IV) that was used to initialize this |
| * cipher or {@code null} if none was used. |
| * |
| * @return the Initialization Vector (IV), or {@code null} if none was used. |
| */ |
| protected abstract byte[] 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 |
| * at all. |
| */ |
| protected abstract AlgorithmParameters engineGetParameters(); |
| |
| /** |
| * Initializes this cipher instance with the specified key 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 or random values |
| * that the specified key cannot provide, the underlying implementation of |
| * this cipher is supposed to generate the required parameters (using its |
| * provider or random values). Random values will be 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 cannot be used to initialize this cipher |
| * instance. |
| */ |
| protected abstract void engineInit(int opmode, Key key, SecureRandom random) |
| throws InvalidKeyException; |
| |
| /** |
| * 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 cannot be used to initialize this cipher |
| * instance. |
| * @throws InvalidAlgorithmParameterException |
| * it the specified parameters are inappropriate for this |
| * cipher. |
| */ |
| protected abstract void engineInit(int opmode, Key key, |
| AlgorithmParameterSpec params, SecureRandom random) |
| throws InvalidKeyException, InvalidAlgorithmParameterException; |
| |
| /** |
| * 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 cannot be used to initialize this cipher |
| * instance. |
| * @throws InvalidAlgorithmParameterException |
| * if the specified parameters are inappropriate for this |
| * cipher. |
| */ |
| protected abstract void engineInit(int opmode, Key key, |
| AlgorithmParameters params, SecureRandom random) |
| throws InvalidKeyException, InvalidAlgorithmParameterException; |
| |
| /** |
| * 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 null, or if {@code inputOffset} and {@code |
| * inputLen} do not specify a valid chunk in the input buffer. |
| */ |
| protected abstract byte[] engineUpdate(byte[] input, int inputOffset, |
| int 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. |
| * @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. |
| */ |
| protected abstract int engineUpdate(byte[] input, int inputOffset, |
| int inputLen, byte[] output, int outputOffset) |
| throws ShortBufferException; |
| |
| /** |
| * 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. |
| */ |
| protected int engineUpdate(ByteBuffer input, ByteBuffer output) |
| throws ShortBufferException { |
| if (input == null) { |
| throw new NullPointerException("input == null"); |
| } |
| if (output == null) { |
| throw new NullPointerException("output == null"); |
| } |
| int position = input.position(); |
| int limit = input.limit(); |
| if ((limit - position) <= 0) { |
| return 0; |
| } |
| byte[] bInput; |
| byte[] bOutput; |
| if (input.hasArray()) { |
| bInput = input.array(); |
| int offset = input.arrayOffset(); |
| bOutput = engineUpdate(bInput, offset + position, limit - position); |
| input.position(limit); |
| } else { |
| bInput = new byte[limit - position]; |
| input.get(bInput); |
| bOutput = engineUpdate(bInput, 0, limit - position); |
| } |
| if (bOutput == null) { |
| return 0; |
| } |
| if (output.remaining() < bOutput.length) { |
| throw new ShortBufferException("output buffer too small"); |
| } |
| try { |
| output.put(bOutput); |
| } catch (java.nio.BufferOverflowException e) { |
| throw new ShortBufferException("output buffer too small"); |
| } |
| return bOutput.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 |
| */ |
| protected void engineUpdateAAD(byte[] input, int inputOffset, int inputLen) { |
| throw new UnsupportedOperationException( |
| "This cipher does not support Authenticated Encryption with Additional Data"); |
| } |
| |
| /** |
| * Continues a multi-part transformation (encryption or decryption). The |
| * {@code input.remaining()} bytes starting at {@code input.position()} are |
| * used for the Additional Authenticated 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 the input buffer to transform. |
| * @since 1.7 |
| */ |
| protected void engineUpdateAAD(ByteBuffer input) { |
| if (input == null) { |
| throw new NullPointerException("input == null"); |
| } |
| int position = input.position(); |
| int limit = input.limit(); |
| if ((limit - position) <= 0) { |
| return; |
| } |
| byte[] bInput; |
| if (input.hasArray()) { |
| bInput = input.array(); |
| int offset = input.arrayOffset(); |
| engineUpdateAAD(bInput, offset + position, limit - position); |
| input.position(limit); |
| } else { |
| int len = limit - position; |
| bInput = new byte[len]; |
| input.get(bInput); |
| engineUpdateAAD(bInput, 0, len); |
| } |
| } |
| |
| /** |
| * 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. |
| */ |
| protected abstract byte[] engineDoFinal(byte[] input, int inputOffset, |
| int inputLen) throws IllegalBlockSizeException, BadPaddingException; |
| |
| /** |
| * 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. |
| */ |
| protected abstract int engineDoFinal(byte[] input, int inputOffset, |
| int inputLen, byte[] output, int outputOffset) |
| throws ShortBufferException, IllegalBlockSizeException, |
| BadPaddingException; |
| |
| /** |
| * 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. |
| */ |
| protected int engineDoFinal(ByteBuffer input, ByteBuffer output) |
| throws ShortBufferException, IllegalBlockSizeException, |
| BadPaddingException { |
| if (input == null) { |
| throw new NullPointerException("input == null"); |
| } |
| if (output == null) { |
| throw new NullPointerException("output == null"); |
| } |
| int position = input.position(); |
| int limit = input.limit(); |
| |
| if ((limit - position) <= 0) { |
| return 0; |
| } |
| byte[] bInput; |
| byte[] bOutput; |
| |
| if (input.hasArray()) { |
| bInput = input.array(); |
| int offset = input.arrayOffset(); |
| bOutput = engineDoFinal(bInput, offset + position, limit - position); |
| input.position(limit); |
| } else { |
| bInput = new byte[limit - position]; |
| input.get(bInput); |
| bOutput = engineDoFinal(bInput, 0, limit - position); |
| } |
| if (output.remaining() < bOutput.length) { |
| throw new ShortBufferException("output buffer too small"); |
| } |
| try { |
| output.put(bOutput); |
| } catch (java.nio.BufferOverflowException e) { |
| throw new ShortBufferException("output buffer too small"); |
| } |
| return bOutput.length; |
| } |
| |
| /** |
| * Wraps a key using this cipher instance. This method has been added to |
| * this class (for backwards compatibility, it cannot be abstract). If this |
| * method is not overridden, it throws an {@code |
| * UnsupportedOperationException}. |
| * |
| * @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 cannot wrap this key. |
| */ |
| protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, InvalidKeyException { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /** |
| * Unwraps a key using this cipher instance. |
| * <p> |
| * This method has been added to this class (for backwards compatibility, it |
| * cannot be abstract). If this method is not overridden, it throws an |
| * {@code UnsupportedOperationException}. |
| * |
| * @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 PRIVATE_KEY} or {@code PUBLIC_KEY}) |
| * @return the unwrapped key. |
| * @throws InvalidKeyException |
| * if the {@code wrappedKey} cannot 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}. |
| */ |
| protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, |
| int wrappedKeyType) throws InvalidKeyException, NoSuchAlgorithmException { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /** |
| * Returns the size of a specified key object in bits. This method has been |
| * added to this class (for backwards compatibility, it cannot be abstract). |
| * If this method is not overridden, it throws an {@code |
| * UnsupportedOperationException}. |
| * |
| * @param key |
| * the key to get the size for. |
| * @return the size of a specified key object in bits. |
| * @throws InvalidKeyException |
| * if the size of the key cannot be determined by this |
| * implementation. |
| */ |
| protected int engineGetKeySize(Key key) throws InvalidKeyException { |
| throw new UnsupportedOperationException(); |
| } |
| } |