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