src.javax.crypto.CipherSpi Maven / Gradle / Ivy
Show all versions of android-all Show documentation
/*
* Copyright (c) 1997, 2013, 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 Service Provider Interface (SPI)
* for the Cipher
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.
*
* In order to create an instance of Cipher
, which
* encapsulates an instance of this CipherSpi
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
* transformation.
* Optionally, the application may also specify the name of a provider.
*
*
A transformation 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., DES), and may be followed by a feedback mode and
* padding scheme.
*
*
A transformation is of the form:
*
*
* - "algorithm/mode/padding" or
*
*
- "algorithm"
*
*
* (in the latter case,
* provider-specific default values for the mode and padding scheme are used).
* For example, the following is a valid transformation:
*
*
* Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding");
*
*
* A provider may supply a separate class for each combination
* of algorithm/mode/padding, or may decide to provide more generic
* classes representing sub-transformations corresponding to
* algorithm or algorithm/mode or algorithm//padding
* (note the double slashes),
* in which case the requested mode and/or padding are set automatically by
* the getInstance
methods of Cipher
, which invoke
* the {@link #engineSetMode(java.lang.String) engineSetMode} and
* {@link #engineSetPadding(java.lang.String) engineSetPadding}
* methods of the provider's subclass of CipherSpi
.
*
*
A Cipher
property in a provider master class may have one of
* the following formats:
*
*
*
* -
*
* // provider's subclass of "CipherSpi" implements "algName" with
* // pluggable mode and padding
* Cipher.
algName
*
*
* -
*
* // provider's subclass of "CipherSpi" implements "algName" in the
* // specified "mode", with pluggable padding
* Cipher.
algName/mode
*
*
* -
*
* // provider's subclass of "CipherSpi" implements "algName" with the
* // specified "padding", with pluggable mode
* Cipher.
algName//padding
*
*
* -
*
* // provider's subclass of "CipherSpi" implements "algName" with the
* // specified "mode" and "padding"
* Cipher.
algName/mode/padding
*
*
*
*
* For example, a provider may supply a subclass of CipherSpi
* that implements DES/ECB/PKCS5Padding, one that implements
* DES/CBC/PKCS5Padding, one that implements
* DES/CFB/PKCS5Padding, and yet another one that implements
* DES/OFB/PKCS5Padding. That provider would have the following
* Cipher
properties in its master class:
*
*
*
* -
*
* Cipher.
DES/ECB/PKCS5Padding
*
*
* -
*
* Cipher.
DES/CBC/PKCS5Padding
*
*
* -
*
* Cipher.
DES/CFB/PKCS5Padding
*
*
* -
*
* Cipher.
DES/OFB/PKCS5Padding
*
*
*
*
* Another provider may implement a class for each of the above modes
* (i.e., one class for ECB, one for CBC, one for CFB,
* and one for OFB), one class for PKCS5Padding,
* and a generic DES class that subclasses from CipherSpi
.
* That provider would have the following
* Cipher
properties in its master class:
*
*
*
* -
*
* Cipher.
DES
*
*
*
*
* The getInstance
factory method of the Cipher
* engine class follows these rules in order to instantiate a provider's
* implementation of CipherSpi
for a
* transformation of the form "algorithm":
*
*
* -
* Check if the provider has registered a subclass of
CipherSpi
* for the specified "algorithm".
* If the answer is YES, instantiate this
* class, for whose mode and padding scheme default values (as supplied by
* the provider) are used.
*
If the answer is NO, throw a NoSuchAlgorithmException
* exception.
*
*
* The getInstance
factory method of the Cipher
* engine class follows these rules in order to instantiate a provider's
* implementation of CipherSpi
for a
* transformation of the form "algorithm/mode/padding":
*
*
* -
* Check if the provider has registered a subclass of
CipherSpi
* for the specified "algorithm/mode/padding" transformation.
* If the answer is YES, instantiate it.
*
If the answer is NO, go to the next step.
*
-
* Check if the provider has registered a subclass of
CipherSpi
* for the sub-transformation "algorithm/mode".
* If the answer is YES, instantiate it, and call
* engineSetPadding(padding)
on the new instance.
*
If the answer is NO, go to the next step.
*
-
* Check if the provider has registered a subclass of
CipherSpi
* for the sub-transformation "algorithm//padding" (note the double
* slashes).
* If the answer is YES, instantiate it, and call
* engineSetMode(mode)
on the new instance.
*
If the answer is NO, go to the next step.
*
-
* Check if the provider has registered a subclass of
CipherSpi
* for the sub-transformation "algorithm".
* If the answer is YES, instantiate it, and call
* engineSetMode(mode)
and
* engineSetPadding(padding)
on the new instance.
*
If the answer is NO, throw a NoSuchAlgorithmException
* exception.
*
*
* @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 update
* or doFinal
operation, given the input length
* inputLen
(in bytes).
*
* This call takes into account any unprocessed (buffered) data from a
* previous update
call, padding, and AEAD tagging.
*
*
The actual output length of the next update
or
* doFinal
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.
*
*
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.
*
*
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.
*
*
The cipher is initialized for one of the following four operations:
* encryption, decryption, key wrapping or key unwrapping, depending on
* the value of opmode
.
*
*
If this cipher requires any algorithm parameters that cannot be
* derived from the given key
, 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
* InvalidKeyException
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).
*
*
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.
*
*
If this cipher (including its underlying feedback or padding scheme)
* requires any random bytes (e.g., for parameter generation), it will get
* them from random
.
*
*
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:
* ENCRYPT_MODE
, DECRYPT_MODE
,
* WRAP_MODE
or UNWRAP_MODE
)
* @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.
*
*
The cipher is initialized for one of the following four operations:
* encryption, decryption, key wrapping or key unwrapping, depending on
* the value of opmode
.
*
*
If this cipher requires any algorithm parameters and
* params
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
* InvalidAlgorithmParameterException
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).
*
*
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.
*
*
If this cipher (including its underlying feedback or padding scheme)
* requires any random bytes (e.g., for parameter generation), it will get
* them from random
.
*
*
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:
* ENCRYPT_MODE
, DECRYPT_MODE
,
* WRAP_MODE
or UNWRAP_MODE
)
* @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 params
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.
*
*
The cipher is initialized for one of the following four operations:
* encryption, decryption, key wrapping or key unwrapping, depending on
* the value of opmode
.
*
*
If this cipher requires any algorithm parameters and
* params
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
* InvalidAlgorithmParameterException
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).
*
*
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.
*
*
If this cipher (including its underlying feedback or padding scheme)
* requires any random bytes (e.g., for parameter generation), it will get
* them from random
.
*
*
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:
* ENCRYPT_MODE
, DECRYPT_MODE
,
* WRAP_MODE
or UNWRAP_MODE
)
* @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 params
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.
*
*
The first inputLen
bytes in the input
* buffer, starting at inputOffset
inclusive, are processed,
* and the result is stored in a new buffer.
*
* @param input the input buffer
* @param inputOffset the offset in input
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.
*
*
The first inputLen
bytes in the input
* buffer, starting at inputOffset
inclusive, are processed,
* and the result is stored in the output
buffer, starting at
* outputOffset
inclusive.
*
*
If the output
buffer is too small to hold the result,
* a ShortBufferException
is thrown.
*
* @param input the input buffer
* @param inputOffset the offset in input
where the input
* starts
* @param inputLen the input length
* @param output the buffer for the result
* @param outputOffset the offset in output
where the result
* is stored
*
* @return the number of bytes stored in output
*
* @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.
*
*
All input.remaining()
bytes starting at
* input.position()
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.
*
*
If output.remaining()
bytes are insufficient to
* hold the result, a ShortBufferException
is thrown.
*
*
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 output
*
* @exception ShortBufferException if there is insufficient space in the
* output buffer
*
* @throws NullPointerException if either parameter is null
* @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.
*
*
The first inputLen
bytes in the input
* buffer, starting at inputOffset
inclusive, and any input
* bytes that may have been buffered during a previous update
* 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.
*
*
Upon finishing, this method resets this cipher object to the state
* it was in when previously initialized via a call to
* engineInit
.
* That is, the object is reset and available to encrypt or decrypt
* (depending on the operation mode that was specified in the call to
* engineInit
) more data.
*
*
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 input
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.
*
*
The first inputLen
bytes in the input
* buffer, starting at inputOffset
inclusive, and any input
* bytes that may have been buffered during a previous update
* 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 output
buffer, starting at
* outputOffset
inclusive.
*
*
If the output
buffer is too small to hold the result,
* a ShortBufferException
is thrown.
*
*
Upon finishing, this method resets this cipher object to the state
* it was in when previously initialized via a call to
* engineInit
.
* That is, the object is reset and available to encrypt or decrypt
* (depending on the operation mode that was specified in the call to
* engineInit
) more data.
*
*
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 input
where the input
* starts
* @param inputLen the input length
* @param output the buffer for the result
* @param outputOffset the offset in output
where the result
* is stored
*
* @return the number of bytes stored in output
*
* @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.
*
*
All input.remaining()
bytes starting at
* input.position()
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.
*
*
If output.remaining()
bytes are insufficient to
* hold the result, a ShortBufferException
is thrown.
*
*
Upon finishing, this method resets this cipher object to the state
* it was in when previously initialized via a call to
* engineInit
.
* That is, the object is reset and available to encrypt or decrypt
* (depending on the operation mode that was specified in the call to
* engineInit
) more data.
*
*
Note: if any exception is thrown, this cipher object may need to
* be reset before it can be used again.
*
*
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 output
*
* @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 null
* @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();
if (a1 && a2) {
byte[] inArray = input.array();
int inOfs = input.arrayOffset() + inPos;
byte[] outArray = output.array();
int outPos = output.position();
int outOfs = output.arrayOffset() + outPos;
int n;
if (isUpdate) {
n = engineUpdate(inArray, inOfs, inLen, outArray, outOfs);
} else {
n = engineDoFinal(inArray, inOfs, inLen, outArray, outOfs);
}
input.position(inLimit);
output.position(outPos + n);
return n;
} else if (!a1 && a2) {
int outPos = output.position();
byte[] outArray = output.array();
int outOfs = output.arrayOffset() + outPos;
byte[] inArray = new byte[getTempArraySize(inLen)];
int total = 0;
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);
return total;
} else { // output is not backed by an accessible byte[]
byte[] inArray;
int inOfs;
if (a1) {
inArray = input.array();
inOfs = input.arrayOffset() + inPos;
} else {
inArray = new byte[getTempArraySize(inLen)];
inOfs = 0;
}
byte[] outArray = new byte[getTempArraySize(outLenNeeded)];
int outSize = outArray.length;
int total = 0;
boolean resized = false;
do {
int chunk =
Math.min(inLen, (outSize == 0? inArray.length : outSize));
if (!a1 && !resized && chunk > 0) {
input.get(inArray, 0, chunk);
inOfs = 0;
}
try {
int n;
if (isUpdate || (inLen != chunk)) {
n = engineUpdate(inArray, inOfs, chunk, outArray, 0);
} else {
n = engineDoFinal(inArray, inOfs, chunk, outArray, 0);
}
resized = false;
inOfs += chunk;
inLen -= chunk;
if (n > 0) {
output.put(outArray, 0, n);
total += n;
}
} catch (ShortBufferException e) {
if (resized) {
// we just resized the output buffer, but it still
// did not work. Bug in the provider, abort
throw (ProviderException)new ProviderException
("Could not determine buffer size").initCause(e);
}
// output buffer is too small, realloc and try again
resized = true;
outSize = engineGetOutputSize(chunk);
outArray = new byte[outSize];
}
} while (inLen > 0);
if (a1) {
input.position(inLimit);
}
return total;
}
}
/**
* Wrap a key.
*
*
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.
*
*
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
* SECRET_KEY
, PRIVATE_KEY
, or
* PUBLIC_KEY
.
*
* @return the unwrapped key.
*
* @exception NoSuchAlgorithmException if no installed providers
* can create keys of type wrappedKeyType
for the
* wrappedKeyAlgorithm
.
*
* @exception InvalidKeyException if wrappedKey
does not
* represent a wrapped key of type wrappedKeyType
for
* the wrappedKeyAlgorithm
.
*
* @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.
*
This concrete method has been added to this previously-defined
* abstract class. It throws an UnsupportedOperationException
* 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 key
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.
*
* 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).
*
* 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).
*
* 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");
}
}