/* |
|
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. |
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
* |
|
* This code is free software; you can redistribute it and/or modify it |
|
* under the terms of the GNU General Public License version 2 only, as |
|
* published by the Free Software Foundation. Oracle designates this |
|
* particular file as subject to the "Classpath" exception as provided |
|
* by Oracle in the LICENSE file that accompanied this code. |
|
* |
|
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
* version 2 for more details (a copy is included in the LICENSE file that |
|
* accompanied this code). |
|
* |
|
* You should have received a copy of the GNU General Public License version |
|
* 2 along with this work; if not, write to the Free Software Foundation, |
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
* |
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
* or visit www.oracle.com if you need additional information or have any |
|
* questions. |
|
*/ |
|
package javax.crypto; |
|
import java.util.StringTokenizer; |
|
import java.util.NoSuchElementException; |
|
import java.security.AlgorithmParameters; |
|
import java.security.Provider; |
|
import java.security.Key; |
|
import java.security.SecureRandom; |
|
import java.security.NoSuchAlgorithmException; |
|
import java.security.NoSuchProviderException; |
|
import java.security.InvalidKeyException; |
|
import java.security.InvalidAlgorithmParameterException; |
|
import java.security.ProviderException; |
|
import java.security.spec.AlgorithmParameterSpec; |
|
import java.nio.ByteBuffer; |
|
/** |
|
* This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) |
|
* for the <code>Cipher</code> class. |
|
* All the abstract methods in this class must be implemented by each |
|
* cryptographic service provider who wishes to supply the implementation |
|
* of a particular cipher algorithm. |
|
* |
|
* <p>In order to create an instance of <code>Cipher</code>, which |
|
* encapsulates an instance of this <code>CipherSpi</code> class, an |
|
* application calls one of the |
|
* {@link Cipher#getInstance(java.lang.String) getInstance} |
|
* factory methods of the |
|
* {@link Cipher Cipher} engine class and specifies the requested |
|
* <i>transformation</i>. |
|
* Optionally, the application may also specify the name of a provider. |
|
* |
|
* <p>A <i>transformation</i> is a string that describes the operation (or |
|
* set of operations) to be performed on the given input, to produce some |
|
* output. A transformation always includes the name of a cryptographic |
|
* algorithm (e.g., <i>AES</i>), and may be followed by a feedback mode and |
|
* padding scheme. |
|
* |
|
* <p> A transformation is of the form: |
|
* |
|
* <ul> |
|
* <li>"<i>algorithm/mode/padding</i>" or |
|
* |
|
* <li>"<i>algorithm</i>" |
|
* </ul> |
|
* |
|
* <P> (in the latter case, |
|
* provider-specific default values for the mode and padding scheme are used). |
|
* For example, the following is a valid transformation: |
|
* |
|
* <pre> |
|
* Cipher c = Cipher.getInstance("<i>AES/CBC/PKCS5Padding</i>"); |
|
* </pre> |
|
* |
|
* <p>A provider may supply a separate class for each combination |
|
* of <i>algorithm/mode/padding</i>, or may decide to provide more generic |
|
* classes representing sub-transformations corresponding to |
|
* <i>algorithm</i> or <i>algorithm/mode</i> or <i>algorithm//padding</i> |
|
* (note the double slashes), |
|
* in which case the requested mode and/or padding are set automatically by |
|
* the <code>getInstance</code> methods of <code>Cipher</code>, which invoke |
|
* the {@link #engineSetMode(java.lang.String) engineSetMode} and |
|
* {@link #engineSetPadding(java.lang.String) engineSetPadding} |
|
* methods of the provider's subclass of <code>CipherSpi</code>. |
|
* |
|
* <p>A <code>Cipher</code> property in a provider master class may have one of |
|
* the following formats: |
|
* |
|
* <ul> |
|
* |
|
* <li> |
|
* <pre> |
|
* // provider's subclass of "CipherSpi" implements "algName" with |
|
* // pluggable mode and padding |
|
* <code>Cipher.</code><i>algName</i> |
|
* </pre> |
|
* |
|
* <li> |
|
* <pre> |
|
* // provider's subclass of "CipherSpi" implements "algName" in the |
|
* // specified "mode", with pluggable padding |
|
* <code>Cipher.</code><i>algName/mode</i> |
|
* </pre> |
|
* |
|
* <li> |
|
* <pre> |
|
* // provider's subclass of "CipherSpi" implements "algName" with the |
|
* // specified "padding", with pluggable mode |
|
* <code>Cipher.</code><i>algName//padding</i> |
|
* </pre> |
|
* |
|
* <li> |
|
* <pre> |
|
* // provider's subclass of "CipherSpi" implements "algName" with the |
|
* // specified "mode" and "padding" |
|
* <code>Cipher.</code><i>algName/mode/padding</i> |
|
* </pre> |
|
* |
|
* </ul> |
|
* |
|
* <p>For example, a provider may supply a subclass of <code>CipherSpi</code> |
|
* that implements <i>AES/ECB/PKCS5Padding</i>, one that implements |
|
* <i>AES/CBC/PKCS5Padding</i>, one that implements |
|
* <i>AES/CFB/PKCS5Padding</i>, and yet another one that implements |
|
* <i>AES/OFB/PKCS5Padding</i>. That provider would have the following |
|
* <code>Cipher</code> properties in its master class: |
|
* |
|
* <ul> |
|
* |
|
* <li> |
|
* <pre> |
|
* <code>Cipher.</code><i>AES/ECB/PKCS5Padding</i> |
|
* </pre> |
|
* |
|
* <li> |
|
* <pre> |
|
* <code>Cipher.</code><i>AES/CBC/PKCS5Padding</i> |
|
* </pre> |
|
* |
|
* <li> |
|
* <pre> |
|
* <code>Cipher.</code><i>AES/CFB/PKCS5Padding</i> |
|
* </pre> |
|
* |
|
* <li> |
|
* <pre> |
|
* <code>Cipher.</code><i>AES/OFB/PKCS5Padding</i> |
|
* </pre> |
|
* |
|
* </ul> |
|
* |
|
* <p>Another provider may implement a class for each of the above modes |
|
* (i.e., one class for <i>ECB</i>, one for <i>CBC</i>, one for <i>CFB</i>, |
|
* and one for <i>OFB</i>), one class for <i>PKCS5Padding</i>, |
|
* and a generic <i>AES</i> class that subclasses from <code>CipherSpi</code>. |
|
* That provider would have the following |
|
* <code>Cipher</code> properties in its master class: |
|
* |
|
* <ul> |
|
* |
|
* <li> |
|
* <pre> |
|
* <code>Cipher.</code><i>AES</i> |
|
* </pre> |
|
* |
|
* </ul> |
|
* |
|
* <p>The <code>getInstance</code> factory method of the <code>Cipher</code> |
|
* engine class follows these rules in order to instantiate a provider's |
|
* implementation of <code>CipherSpi</code> for a |
|
* transformation of the form "<i>algorithm</i>": |
|
* |
|
* <ol> |
|
* <li> |
|
* Check if the provider has registered a subclass of <code>CipherSpi</code> |
|
* for the specified "<i>algorithm</i>". |
|
* <p>If the answer is YES, instantiate this |
|
* class, for whose mode and padding scheme default values (as supplied by |
|
* the provider) are used. |
|
* <p>If the answer is NO, throw a <code>NoSuchAlgorithmException</code> |
|
* exception. |
|
* </ol> |
|
* |
|
* <p>The <code>getInstance</code> factory method of the <code>Cipher</code> |
|
* engine class follows these rules in order to instantiate a provider's |
|
* implementation of <code>CipherSpi</code> for a |
|
* transformation of the form "<i>algorithm/mode/padding</i>": |
|
* |
|
* <ol> |
|
* <li> |
|
* Check if the provider has registered a subclass of <code>CipherSpi</code> |
|
* for the specified "<i>algorithm/mode/padding</i>" transformation. |
|
* <p>If the answer is YES, instantiate it. |
|
* <p>If the answer is NO, go to the next step. |
|
* <li> |
|
* Check if the provider has registered a subclass of <code>CipherSpi</code> |
|
* for the sub-transformation "<i>algorithm/mode</i>". |
|
* <p>If the answer is YES, instantiate it, and call |
|
* <code>engineSetPadding(<i>padding</i>)</code> on the new instance. |
|
* <p>If the answer is NO, go to the next step. |
|
* <li> |
|
* Check if the provider has registered a subclass of <code>CipherSpi</code> |
|
* for the sub-transformation "<i>algorithm//padding</i>" (note the double |
|
* slashes). |
|
* <p>If the answer is YES, instantiate it, and call |
|
* <code>engineSetMode(<i>mode</i>)</code> on the new instance. |
|
* <p>If the answer is NO, go to the next step. |
|
* <li> |
|
* Check if the provider has registered a subclass of <code>CipherSpi</code> |
|
* for the sub-transformation "<i>algorithm</i>". |
|
* <p>If the answer is YES, instantiate it, and call |
|
* <code>engineSetMode(<i>mode</i>)</code> and |
|
* <code>engineSetPadding(<i>padding</i>)</code> on the new instance. |
|
* <p>If the answer is NO, throw a <code>NoSuchAlgorithmException</code> |
|
* exception. |
|
* </ol> |
|
* |
|
* @author Jan Luehe |
|
* @see KeyGenerator |
|
* @see SecretKey |
|
* @since 1.4 |
|
*/ |
|
public abstract class CipherSpi { |
|
/** |
|
* Sets the mode of this cipher. |
|
* |
|
* @param mode the cipher mode |
|
* |
|
* @exception NoSuchAlgorithmException if the requested cipher mode does |
|
* not exist |
|
*/ |
|
protected abstract void engineSetMode(String mode) |
|
throws NoSuchAlgorithmException; |
|
/** |
|
* Sets the padding mechanism of this cipher. |
|
* |
|
* @param padding the padding mechanism |
|
* |
|
* @exception NoSuchPaddingException if the requested padding mechanism |
|
* does not exist |
|
*/ |
|
protected abstract void engineSetPadding(String padding) |
|
throws NoSuchPaddingException; |
|
/** |
|
* Returns the block size (in bytes). |
|
* |
|
* @return the block size (in bytes), or 0 if the underlying algorithm is |
|
* not a block cipher |
|
*/ |
|
protected abstract int engineGetBlockSize(); |
|
/** |
|
* Returns the length in bytes that an output buffer would |
|
* need to be in order to hold the result of the next <code>update</code> |
|
* or <code>doFinal</code> operation, given the input length |
|
* <code>inputLen</code> (in bytes). |
|
* |
|
* <p>This call takes into account any unprocessed (buffered) data from a |
|
* previous <code>update</code> call, padding, and AEAD tagging. |
|
* |
|
* <p>The actual output length of the next <code>update</code> or |
|
* <code>doFinal</code> call may be smaller than the length returned by |
|
* this method. |
|
* |
|
* @param inputLen the input length (in bytes) |
|
* |
|
* @return the required output buffer size (in bytes) |
|
*/ |
|
protected abstract int engineGetOutputSize(int inputLen); |
|
/** |
|
* Returns the initialization vector (IV) in a new buffer. |
|
* |
|
* <p> This is useful in the context of password-based encryption or |
|
* decryption, where the IV is derived from a user-provided passphrase. |
|
* |
|
* @return the initialization vector in a new buffer, or null if the |
|
* underlying algorithm does not use an IV, or if the IV has not yet |
|
* been set. |
|
*/ |
|
protected abstract byte[] engineGetIV(); |
|
/** |
|
* Returns the parameters used with this cipher. |
|
* |
|
* <p>The returned parameters may be the same that were used to initialize |
|
* this cipher, or may contain a combination of default and random |
|
* parameter values used by the underlying cipher implementation if this |
|
* cipher requires algorithm parameters but was not initialized with any. |
|
* |
|
* @return the parameters used with this cipher, or null if this cipher |
|
* does not use any parameters. |
|
*/ |
|
protected abstract AlgorithmParameters engineGetParameters(); |
|
/** |
|
* Initializes this cipher with a key and a source |
|
* of randomness. |
|
* |
|
* <p>The cipher is initialized for one of the following four operations: |
|
* encryption, decryption, key wrapping or key unwrapping, depending on |
|
* the value of <code>opmode</code>. |
|
* |
|
* <p>If this cipher requires any algorithm parameters that cannot be |
|
* derived from the given <code>key</code>, the underlying cipher |
|
* implementation is supposed to generate the required parameters itself |
|
* (using provider-specific default or random values) if it is being |
|
* initialized for encryption or key wrapping, and raise an |
|
* <code>InvalidKeyException</code> if it is being |
|
* initialized for decryption or key unwrapping. |
|
* The generated parameters can be retrieved using |
|
* {@link #engineGetParameters() engineGetParameters} or |
|
* {@link #engineGetIV() engineGetIV} (if the parameter is an IV). |
|
* |
|
* <p>If this cipher requires algorithm parameters that cannot be |
|
* derived from the input parameters, and there are no reasonable |
|
* provider-specific default values, initialization will |
|
* necessarily fail. |
|
* |
|
* <p>If this cipher (including its underlying feedback or padding scheme) |
|
* requires any random bytes (e.g., for parameter generation), it will get |
|
* them from <code>random</code>. |
|
* |
|
* <p>Note that when a Cipher object is initialized, it loses all |
|
* previously-acquired state. In other words, initializing a Cipher is |
|
* equivalent to creating a new instance of that Cipher and initializing |
|
* it. |
|
* |
|
* @param opmode the operation mode of this cipher (this is one of |
|
* the following: |
|
* <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>, |
|
* <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>) |
|
* @param key the encryption key |
|
* @param random the source of randomness |
|
* |
|
* @exception InvalidKeyException if the given key is inappropriate for |
|
* initializing this cipher, or requires |
|
* algorithm parameters that cannot be |
|
* determined from the given key. |
|
* @throws UnsupportedOperationException if {@code opmode} is |
|
* {@code WRAP_MODE} or {@code UNWRAP_MODE} is not implemented |
|
* by the cipher. |
|
*/ |
|
protected abstract void engineInit(int opmode, Key key, |
|
SecureRandom random) |
|
throws InvalidKeyException; |
|
/** |
|
* Initializes this cipher with a key, a set of |
|
* algorithm parameters, and a source of randomness. |
|
* |
|
* <p>The cipher is initialized for one of the following four operations: |
|
* encryption, decryption, key wrapping or key unwrapping, depending on |
|
* the value of <code>opmode</code>. |
|
* |
|
* <p>If this cipher requires any algorithm parameters and |
|
* <code>params</code> is null, the underlying cipher implementation is |
|
* supposed to generate the required parameters itself (using |
|
* provider-specific default or random values) if it is being |
|
* initialized for encryption or key wrapping, and raise an |
|
* <code>InvalidAlgorithmParameterException</code> if it is being |
|
* initialized for decryption or key unwrapping. |
|
* The generated parameters can be retrieved using |
|
* {@link #engineGetParameters() engineGetParameters} or |
|
* {@link #engineGetIV() engineGetIV} (if the parameter is an IV). |
|
* |
|
* <p>If this cipher requires algorithm parameters that cannot be |
|
* derived from the input parameters, and there are no reasonable |
|
* provider-specific default values, initialization will |
|
* necessarily fail. |
|
* |
|
* <p>If this cipher (including its underlying feedback or padding scheme) |
|
* requires any random bytes (e.g., for parameter generation), it will get |
|
* them from <code>random</code>. |
|
* |
|
* <p>Note that when a Cipher object is initialized, it loses all |
|
* previously-acquired state. In other words, initializing a Cipher is |
|
* equivalent to creating a new instance of that Cipher and initializing |
|
* it. |
|
* |
|
* @param opmode the operation mode of this cipher (this is one of |
|
* the following: |
|
* <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>, |
|
* <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>) |
|
* @param key the encryption key |
|
* @param params the algorithm parameters |
|
* @param random the source of randomness |
|
* |
|
* @exception InvalidKeyException if the given key is inappropriate for |
|
* initializing this cipher |
|
* @exception InvalidAlgorithmParameterException if the given algorithm |
|
* parameters are inappropriate for this cipher, |
|
* or if this cipher requires |
|
* algorithm parameters and <code>params</code> is null. |
|
* @throws UnsupportedOperationException if {@code opmode} is |
|
* {@code WRAP_MODE} or {@code UNWRAP_MODE} is not implemented |
|
* by the cipher. |
|
*/ |
|
protected abstract void engineInit(int opmode, Key key, |
|
AlgorithmParameterSpec params, |
|
SecureRandom random) |
|
throws InvalidKeyException, InvalidAlgorithmParameterException; |
|
/** |
|
* Initializes this cipher with a key, a set of |
|
* algorithm parameters, and a source of randomness. |
|
* |
|
* <p>The cipher is initialized for one of the following four operations: |
|
* encryption, decryption, key wrapping or key unwrapping, depending on |
|
* the value of <code>opmode</code>. |
|
* |
|
* <p>If this cipher requires any algorithm parameters and |
|
* <code>params</code> is null, the underlying cipher implementation is |
|
* supposed to generate the required parameters itself (using |
|
* provider-specific default or random values) if it is being |
|
* initialized for encryption or key wrapping, and raise an |
|
* <code>InvalidAlgorithmParameterException</code> if it is being |
|
* initialized for decryption or key unwrapping. |
|
* The generated parameters can be retrieved using |
|
* {@link #engineGetParameters() engineGetParameters} or |
|
* {@link #engineGetIV() engineGetIV} (if the parameter is an IV). |
|
* |
|
* <p>If this cipher requires algorithm parameters that cannot be |
|
* derived from the input parameters, and there are no reasonable |
|
* provider-specific default values, initialization will |
|
* necessarily fail. |
|
* |
|
* <p>If this cipher (including its underlying feedback or padding scheme) |
|
* requires any random bytes (e.g., for parameter generation), it will get |
|
* them from <code>random</code>. |
|
* |
|
* <p>Note that when a Cipher object is initialized, it loses all |
|
* previously-acquired state. In other words, initializing a Cipher is |
|
* equivalent to creating a new instance of that Cipher and initializing |
|
* it. |
|
* |
|
* @param opmode the operation mode of this cipher (this is one of |
|
* the following: |
|
* <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>, |
|
* <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>) |
|
* @param key the encryption key |
|
* @param params the algorithm parameters |
|
* @param random the source of randomness |
|
* |
|
* @exception InvalidKeyException if the given key is inappropriate for |
|
* initializing this cipher |
|
* @exception InvalidAlgorithmParameterException if the given algorithm |
|
* parameters are inappropriate for this cipher, |
|
* or if this cipher requires |
|
* algorithm parameters and <code>params</code> is null. |
|
* @throws UnsupportedOperationException if {@code opmode} is |
|
* {@code WRAP_MODE} or {@code UNWRAP_MODE} is not implemented |
|
* by the cipher. |
|
*/ |
|
protected abstract void engineInit(int opmode, Key key, |
|
AlgorithmParameters params, |
|
SecureRandom random) |
|
throws InvalidKeyException, InvalidAlgorithmParameterException; |
|
/** |
|
* Continues a multiple-part encryption or decryption operation |
|
* (depending on how this cipher was initialized), processing another data |
|
* part. |
|
* |
|
* <p>The first <code>inputLen</code> bytes in the <code>input</code> |
|
* buffer, starting at <code>inputOffset</code> inclusive, are processed, |
|
* and the result is stored in a new buffer. |
|
* |
|
* @param input the input buffer |
|
* @param inputOffset the offset in <code>input</code> where the input |
|
* starts |
|
* @param inputLen the input length |
|
* |
|
* @return the new buffer with the result, or null if the underlying |
|
* cipher is a block cipher and the input data is too short to result in a |
|
* new block. |
|
*/ |
|
protected abstract byte[] engineUpdate(byte[] input, int inputOffset, |
|
int inputLen); |
|
/** |
|
* Continues a multiple-part encryption or decryption operation |
|
* (depending on how this cipher was initialized), processing another data |
|
* part. |
|
* |
|
* <p>The first <code>inputLen</code> bytes in the <code>input</code> |
|
* buffer, starting at <code>inputOffset</code> inclusive, are processed, |
|
* and the result is stored in the <code>output</code> buffer, starting at |
|
* <code>outputOffset</code> inclusive. |
|
* |
|
* <p>If the <code>output</code> buffer is too small to hold the result, |
|
* a <code>ShortBufferException</code> is thrown. |
|
* |
|
* @param input the input buffer |
|
* @param inputOffset the offset in <code>input</code> where the input |
|
* starts |
|
* @param inputLen the input length |
|
* @param output the buffer for the result |
|
* @param outputOffset the offset in <code>output</code> where the result |
|
* is stored |
|
* |
|
* @return the number of bytes stored in <code>output</code> |
|
* |
|
* @exception ShortBufferException if the given output buffer is too small |
|
* to hold the result |
|
*/ |
|
protected abstract int engineUpdate(byte[] input, int inputOffset, |
|
int inputLen, byte[] output, |
|
int outputOffset) |
|
throws ShortBufferException; |
|
/** |
|
* Continues a multiple-part encryption or decryption operation |
|
* (depending on how this cipher was initialized), processing another data |
|
* part. |
|
* |
|
* <p>All <code>input.remaining()</code> bytes starting at |
|
* <code>input.position()</code> are processed. The result is stored |
|
* in the output buffer. |
|
* Upon return, the input buffer's position will be equal |
|
* to its limit; its limit will not have changed. The output buffer's |
|
* position will have advanced by n, where n is the value returned |
|
* by this method; the output buffer's limit will not have changed. |
|
* |
|
* <p>If <code>output.remaining()</code> bytes are insufficient to |
|
* hold the result, a <code>ShortBufferException</code> is thrown. |
|
* |
|
* <p>Subclasses should consider overriding this method if they can |
|
* process ByteBuffers more efficiently than byte arrays. |
|
* |
|
* @param input the input ByteBuffer |
|
* @param output the output ByteByffer |
|
* |
|
* @return the number of bytes stored in <code>output</code> |
|
* |
|
* @exception ShortBufferException if there is insufficient space in the |
|
* output buffer |
|
* |
|
* @throws NullPointerException if either parameter is <CODE>null</CODE> |
|
* @since 1.5 |
|
*/ |
|
protected int engineUpdate(ByteBuffer input, ByteBuffer output) |
|
throws ShortBufferException { |
|
try { |
|
return bufferCrypt(input, output, true); |
|
} catch (IllegalBlockSizeException e) { |
|
// never thrown for engineUpdate() |
|
throw new ProviderException("Internal error in update()"); |
|
} catch (BadPaddingException e) { |
|
// never thrown for engineUpdate() |
|
throw new ProviderException("Internal error in update()"); |
|
} |
|
} |
|
/** |
|
* Encrypts or decrypts data in a single-part operation, |
|
* or finishes a multiple-part operation. |
|
* The data is encrypted or decrypted, depending on how this cipher was |
|
* initialized. |
|
* |
|
* <p>The first <code>inputLen</code> bytes in the <code>input</code> |
|
* buffer, starting at <code>inputOffset</code> inclusive, and any input |
|
* bytes that may have been buffered during a previous <code>update</code> |
|
* operation, are processed, with padding (if requested) being applied. |
|
* If an AEAD mode such as GCM/CCM is being used, the authentication |
|
* tag is appended in the case of encryption, or verified in the |
|
* case of decryption. |
|
* The result is stored in a new buffer. |
|
* |
|
* <p>Upon finishing, this method resets this cipher object to the state |
|
* it was in when previously initialized via a call to |
|
* <code>engineInit</code>. |
|
* That is, the object is reset and available to encrypt or decrypt |
|
* (depending on the operation mode that was specified in the call to |
|
* <code>engineInit</code>) more data. |
|
* |
|
* <p>Note: if any exception is thrown, this cipher object may need to |
|
* be reset before it can be used again. |
|
* |
|
* @param input the input buffer |
|
* @param inputOffset the offset in <code>input</code> where the input |
|
* starts |
|
* @param inputLen the input length |
|
* |
|
* @return the new buffer with the result |
|
* |
|
* @exception IllegalBlockSizeException if this cipher is a block cipher, |
|
* no padding has been requested (only in encryption mode), and the total |
|
* input length of the data processed by this cipher is not a multiple of |
|
* block size; or if this encryption algorithm is unable to |
|
* process the input data provided. |
|
* @exception BadPaddingException if this cipher is in decryption mode, |
|
* and (un)padding has been requested, but the decrypted data is not |
|
* bounded by the appropriate padding bytes |
|
* @exception AEADBadTagException if this cipher is decrypting in an |
|
* AEAD mode (such as GCM/CCM), and the received authentication tag |
|
* does not match the calculated value |
|
*/ |
|
protected abstract byte[] engineDoFinal(byte[] input, int inputOffset, |
|
int inputLen) |
|
throws IllegalBlockSizeException, BadPaddingException; |
|
/** |
|
* Encrypts or decrypts data in a single-part operation, |
|
* or finishes a multiple-part operation. |
|
* The data is encrypted or decrypted, depending on how this cipher was |
|
* initialized. |
|
* |
|
* <p>The first <code>inputLen</code> bytes in the <code>input</code> |
|
* buffer, starting at <code>inputOffset</code> inclusive, and any input |
|
* bytes that may have been buffered during a previous <code>update</code> |
|
* operation, are processed, with padding (if requested) being applied. |
|
* If an AEAD mode such as GCM/CCM is being used, the authentication |
|
* tag is appended in the case of encryption, or verified in the |
|
* case of decryption. |
|
* The result is stored in the <code>output</code> buffer, starting at |
|
* <code>outputOffset</code> inclusive. |
|
* |
|
* <p>If the <code>output</code> buffer is too small to hold the result, |
|
* a <code>ShortBufferException</code> is thrown. |
|
* |
|
* <p>Upon finishing, this method resets this cipher object to the state |
|
* it was in when previously initialized via a call to |
|
* <code>engineInit</code>. |
|
* That is, the object is reset and available to encrypt or decrypt |
|
* (depending on the operation mode that was specified in the call to |
|
* <code>engineInit</code>) more data. |
|
* |
|
* <p>Note: if any exception is thrown, this cipher object may need to |
|
* be reset before it can be used again. |
|
* |
|
* @param input the input buffer |
|
* @param inputOffset the offset in <code>input</code> where the input |
|
* starts |
|
* @param inputLen the input length |
|
* @param output the buffer for the result |
|
* @param outputOffset the offset in <code>output</code> where the result |
|
* is stored |
|
* |
|
* @return the number of bytes stored in <code>output</code> |
|
* |
|
* @exception IllegalBlockSizeException if this cipher is a block cipher, |
|
* no padding has been requested (only in encryption mode), and the total |
|
* input length of the data processed by this cipher is not a multiple of |
|
* block size; or if this encryption algorithm is unable to |
|
* process the input data provided. |
|
* @exception ShortBufferException if the given output buffer is too small |
|
* to hold the result |
|
* @exception BadPaddingException if this cipher is in decryption mode, |
|
* and (un)padding has been requested, but the decrypted data is not |
|
* bounded by the appropriate padding bytes |
|
* @exception AEADBadTagException if this cipher is decrypting in an |
|
* AEAD mode (such as GCM/CCM), and the received authentication tag |
|
* does not match the calculated value |
|
*/ |
|
protected abstract int engineDoFinal(byte[] input, int inputOffset, |
|
int inputLen, byte[] output, |
|
int outputOffset) |
|
throws ShortBufferException, IllegalBlockSizeException, |
|
BadPaddingException; |
|
/** |
|
* Encrypts or decrypts data in a single-part operation, |
|
* or finishes a multiple-part operation. |
|
* The data is encrypted or decrypted, depending on how this cipher was |
|
* initialized. |
|
* |
|
* <p>All <code>input.remaining()</code> bytes starting at |
|
* <code>input.position()</code> are processed. |
|
* If an AEAD mode such as GCM/CCM is being used, the authentication |
|
* tag is appended in the case of encryption, or verified in the |
|
* case of decryption. |
|
* The result is stored in the output buffer. |
|
* Upon return, the input buffer's position will be equal |
|
* to its limit; its limit will not have changed. The output buffer's |
|
* position will have advanced by n, where n is the value returned |
|
* by this method; the output buffer's limit will not have changed. |
|
* |
|
* <p>If <code>output.remaining()</code> bytes are insufficient to |
|
* hold the result, a <code>ShortBufferException</code> is thrown. |
|
* |
|
* <p>Upon finishing, this method resets this cipher object to the state |
|
* it was in when previously initialized via a call to |
|
* <code>engineInit</code>. |
|
* That is, the object is reset and available to encrypt or decrypt |
|
* (depending on the operation mode that was specified in the call to |
|
* <code>engineInit</code>) more data. |
|
* |
|
* <p>Note: if any exception is thrown, this cipher object may need to |
|
* be reset before it can be used again. |
|
* |
|
* <p>Subclasses should consider overriding this method if they can |
|
* process ByteBuffers more efficiently than byte arrays. |
|
* |
|
* @param input the input ByteBuffer |
|
* @param output the output ByteByffer |
|
* |
|
* @return the number of bytes stored in <code>output</code> |
|
* |
|
* @exception IllegalBlockSizeException if this cipher is a block cipher, |
|
* no padding has been requested (only in encryption mode), and the total |
|
* input length of the data processed by this cipher is not a multiple of |
|
* block size; or if this encryption algorithm is unable to |
|
* process the input data provided. |
|
* @exception ShortBufferException if there is insufficient space in the |
|
* output buffer |
|
* @exception BadPaddingException if this cipher is in decryption mode, |
|
* and (un)padding has been requested, but the decrypted data is not |
|
* bounded by the appropriate padding bytes |
|
* @exception AEADBadTagException if this cipher is decrypting in an |
|
* AEAD mode (such as GCM/CCM), and the received authentication tag |
|
* does not match the calculated value |
|
* |
|
* @throws NullPointerException if either parameter is <CODE>null</CODE> |
|
* @since 1.5 |
|
*/ |
|
protected int engineDoFinal(ByteBuffer input, ByteBuffer output) |
|
throws ShortBufferException, IllegalBlockSizeException, |
|
BadPaddingException { |
|
return bufferCrypt(input, output, false); |
|
} |
|
// copied from sun.security.jca.JCAUtil |
|
// will be changed to reference that method once that code has been |
|
// integrated and promoted |
|
static int getTempArraySize(int totalSize) { |
|
return Math.min(4096, totalSize); |
|
} |
|
/** |
|
* Implementation for encryption using ByteBuffers. Used for both |
|
* engineUpdate() and engineDoFinal(). |
|
*/ |
|
private int bufferCrypt(ByteBuffer input, ByteBuffer output, |
|
boolean isUpdate) throws ShortBufferException, |
|
IllegalBlockSizeException, BadPaddingException { |
|
if ((input == null) || (output == null)) { |
|
throw new NullPointerException |
|
("Input and output buffers must not be null"); |
|
} |
|
int inPos = input.position(); |
|
int inLimit = input.limit(); |
|
int inLen = inLimit - inPos; |
|
if (isUpdate && (inLen == 0)) { |
|
return 0; |
|
} |
|
int outLenNeeded = engineGetOutputSize(inLen); |
|
if (output.remaining() < outLenNeeded) { |
|
throw new ShortBufferException("Need at least " + outLenNeeded |
|
+ " bytes of space in output buffer"); |
|
} |
|
boolean a1 = input.hasArray(); |
|
boolean a2 = output.hasArray(); |
|
int total = 0; |
|
byte[] inArray, outArray; |
|
if (a2) { // output has an accessible byte[] |
|
outArray = output.array(); |
|
int outPos = output.position(); |
|
int outOfs = output.arrayOffset() + outPos; |
|
if (a1) { // input also has an accessible byte[] |
|
inArray = input.array(); |
|
int inOfs = input.arrayOffset() + inPos; |
|
if (isUpdate) { |
|
total = engineUpdate(inArray, inOfs, inLen, outArray, outOfs); |
|
} else { |
|
total = engineDoFinal(inArray, inOfs, inLen, outArray, outOfs); |
|
} |
|
input.position(inLimit); |
|
} else { // input does not have accessible byte[] |
|
inArray = new byte[getTempArraySize(inLen)]; |
|
do { |
|
int chunk = Math.min(inLen, inArray.length); |
|
if (chunk > 0) { |
|
input.get(inArray, 0, chunk); |
|
} |
|
int n; |
|
if (isUpdate || (inLen > chunk)) { |
|
n = engineUpdate(inArray, 0, chunk, outArray, outOfs); |
|
} else { |
|
n = engineDoFinal(inArray, 0, chunk, outArray, outOfs); |
|
} |
|
total += n; |
|
outOfs += n; |
|
inLen -= chunk; |
|
} while (inLen > 0); |
|
} |
|
output.position(outPos + total); |
|
} else { // output does not have an accessible byte[] |
|
if (a1) { // but input has an accessible byte[] |
|
inArray = input.array(); |
|
int inOfs = input.arrayOffset() + inPos; |
|
if (isUpdate) { |
|
outArray = engineUpdate(inArray, inOfs, inLen); |
|
} else { |
|
outArray = engineDoFinal(inArray, inOfs, inLen); |
|
} |
|
input.position(inLimit); |
|
if (outArray != null && outArray.length != 0) { |
|
output.put(outArray); |
|
total = outArray.length; |
|
} |
|
} else { // input also does not have an accessible byte[] |
|
inArray = new byte[getTempArraySize(inLen)]; |
|
do { |
|
int chunk = Math.min(inLen, inArray.length); |
|
if (chunk > 0) { |
|
input.get(inArray, 0, chunk); |
|
} |
|
int n; |
|
if (isUpdate || (inLen > chunk)) { |
|
outArray = engineUpdate(inArray, 0, chunk); |
|
} else { |
|
outArray = engineDoFinal(inArray, 0, chunk); |
|
} |
|
if (outArray != null && outArray.length != 0) { |
|
output.put(outArray); |
|
total += outArray.length; |
|
} |
|
inLen -= chunk; |
|
} while (inLen > 0); |
|
} |
|
} |
|
return total; |
|
} |
|
/** |
|
* Wrap a key. |
|
* |
|
* <p>This concrete method has been added to this previously-defined |
|
* abstract class. (For backwards compatibility, it cannot be abstract.) |
|
* It may be overridden by a provider to wrap a key. |
|
* Such an override is expected to throw an IllegalBlockSizeException or |
|
* InvalidKeyException (under the specified circumstances), |
|
* if the given key cannot be wrapped. |
|
* If this method is not overridden, it always throws an |
|
* UnsupportedOperationException. |
|
* |
|
* @param key the key to be wrapped. |
|
* |
|
* @return the wrapped key. |
|
* |
|
* @exception IllegalBlockSizeException if this cipher is a block cipher, |
|
* no padding has been requested, and the length of the encoding of the |
|
* key to be wrapped is not a multiple of the block size. |
|
* |
|
* @exception InvalidKeyException if it is impossible or unsafe to |
|
* wrap the key with this cipher (e.g., a hardware protected key is |
|
* being passed to a software-only cipher). |
|
* |
|
* @throws UnsupportedOperationException if this method is not supported. |
|
*/ |
|
protected byte[] engineWrap(Key key) |
|
throws IllegalBlockSizeException, InvalidKeyException |
|
{ |
|
throw new UnsupportedOperationException(); |
|
} |
|
/** |
|
* Unwrap a previously wrapped key. |
|
* |
|
* <p>This concrete method has been added to this previously-defined |
|
* abstract class. (For backwards compatibility, it cannot be abstract.) |
|
* It may be overridden by a provider to unwrap a previously wrapped key. |
|
* Such an override is expected to throw an InvalidKeyException if |
|
* the given wrapped key cannot be unwrapped. |
|
* If this method is not overridden, it always throws an |
|
* UnsupportedOperationException. |
|
* |
|
* @param wrappedKey the key to be unwrapped. |
|
* |
|
* @param wrappedKeyAlgorithm the algorithm associated with the wrapped |
|
* key. |
|
* |
|
* @param wrappedKeyType the type of the wrapped key. This is one of |
|
* <code>SECRET_KEY</code>, <code>PRIVATE_KEY</code>, or |
|
* <code>PUBLIC_KEY</code>. |
|
* |
|
* @return the unwrapped key. |
|
* |
|
* @exception NoSuchAlgorithmException if no installed providers |
|
* can create keys of type <code>wrappedKeyType</code> for the |
|
* <code>wrappedKeyAlgorithm</code>. |
|
* |
|
* @exception InvalidKeyException if <code>wrappedKey</code> does not |
|
* represent a wrapped key of type <code>wrappedKeyType</code> for |
|
* the <code>wrappedKeyAlgorithm</code>. |
|
* |
|
* @throws UnsupportedOperationException if this method is not supported. |
|
*/ |
|
protected Key engineUnwrap(byte[] wrappedKey, |
|
String wrappedKeyAlgorithm, |
|
int wrappedKeyType) |
|
throws InvalidKeyException, NoSuchAlgorithmException |
|
{ |
|
throw new UnsupportedOperationException(); |
|
} |
|
/** |
|
* Returns the key size of the given key object in bits. |
|
* <p>This concrete method has been added to this previously-defined |
|
* abstract class. It throws an <code>UnsupportedOperationException</code> |
|
* if it is not overridden by the provider. |
|
* |
|
* @param key the key object. |
|
* |
|
* @return the key size of the given key object. |
|
* |
|
* @exception InvalidKeyException if <code>key</code> is invalid. |
|
*/ |
|
protected int engineGetKeySize(Key key) |
|
throws InvalidKeyException |
|
{ |
|
throw new UnsupportedOperationException(); |
|
} |
|
/** |
|
* Continues a multi-part update of the Additional Authentication |
|
* Data (AAD), using a subset of the provided buffer. |
|
* <p> |
|
* Calls to this method provide AAD to the cipher when operating in |
|
* modes such as AEAD (GCM/CCM). If this cipher is operating in |
|
* either GCM or CCM mode, all AAD must be supplied before beginning |
|
* operations on the ciphertext (via the {@code update} and {@code |
|
* doFinal} methods). |
|
* |
|
* @param src the buffer containing the AAD |
|
* @param offset the offset in {@code src} where the AAD input starts |
|
* @param len the number of AAD bytes |
|
* |
|
* @throws IllegalStateException if this cipher is in a wrong state |
|
* (e.g., has not been initialized), does not accept AAD, or if |
|
* operating in either GCM or CCM mode and one of the {@code update} |
|
* methods has already been called for the active |
|
* encryption/decryption operation |
|
* @throws UnsupportedOperationException if this method |
|
* has not been overridden by an implementation |
|
* |
|
* @since 1.7 |
|
*/ |
|
protected void engineUpdateAAD(byte[] src, int offset, int len) { |
|
throw new UnsupportedOperationException( |
|
"The underlying Cipher implementation " |
|
+ "does not support this method"); |
|
} |
|
/** |
|
* Continues a multi-part update of the Additional Authentication |
|
* Data (AAD). |
|
* <p> |
|
* Calls to this method provide AAD to the cipher when operating in |
|
* modes such as AEAD (GCM/CCM). If this cipher is operating in |
|
* either GCM or CCM mode, all AAD must be supplied before beginning |
|
* operations on the ciphertext (via the {@code update} and {@code |
|
* doFinal} methods). |
|
* <p> |
|
* All {@code src.remaining()} bytes starting at |
|
* {@code src.position()} are processed. |
|
* Upon return, the input buffer's position will be equal |
|
* to its limit; its limit will not have changed. |
|
* |
|
* @param src the buffer containing the AAD |
|
* |
|
* @throws IllegalStateException if this cipher is in a wrong state |
|
* (e.g., has not been initialized), does not accept AAD, or if |
|
* operating in either GCM or CCM mode and one of the {@code update} |
|
* methods has already been called for the active |
|
* encryption/decryption operation |
|
* @throws UnsupportedOperationException if this method |
|
* has not been overridden by an implementation |
|
* |
|
* @since 1.7 |
|
*/ |
|
protected void engineUpdateAAD(ByteBuffer src) { |
|
throw new UnsupportedOperationException( |
|
"The underlying Cipher implementation " |
|
+ "does not support this method"); |
|
} |
|
} |