/* * 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 Service Provider Interface (SPI) for * cryptographic ciphers. *
* 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 transformation, 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: *
* When one of the {@link Cipher#getInstance} factory methods is called with a * transformation that is only an algorithm, check if the provider * defines a {@code CipherSpi} for "algorithm", if so: return it, otherwise * throw a {@link NoSuchAlgorithmException}. *
* The following rules apply when a transformation is of the form * "algorithm/mode/padding": *
* 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. *
* 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. *
* 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 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}; *
* 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. *
* 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 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. *
* 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 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. *
* 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. *
* 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. *
* 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. *
* 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). *
* 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). *
* 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). *
* 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. *
* 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(); } }