Path: blob/master/src/java.base/share/classes/javax/crypto/CipherSpi.java
41152 views
/*1* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.crypto;2627import java.util.StringTokenizer;28import java.util.NoSuchElementException;29import java.security.AlgorithmParameters;30import java.security.Provider;31import java.security.Key;32import java.security.SecureRandom;33import java.security.NoSuchAlgorithmException;34import java.security.NoSuchProviderException;35import java.security.InvalidKeyException;36import java.security.InvalidAlgorithmParameterException;37import java.security.ProviderException;38import java.security.spec.AlgorithmParameterSpec;3940import java.nio.ByteBuffer;4142/**43* This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)44* for the <code>Cipher</code> class.45* All the abstract methods in this class must be implemented by each46* cryptographic service provider who wishes to supply the implementation47* of a particular cipher algorithm.48*49* <p>In order to create an instance of <code>Cipher</code>, which50* encapsulates an instance of this <code>CipherSpi</code> class, an51* application calls one of the52* {@link Cipher#getInstance(java.lang.String) getInstance}53* factory methods of the54* {@link Cipher Cipher} engine class and specifies the requested55* <i>transformation</i>.56* Optionally, the application may also specify the name of a provider.57*58* <p>A <i>transformation</i> is a string that describes the operation (or59* set of operations) to be performed on the given input, to produce some60* output. A transformation always includes the name of a cryptographic61* algorithm (e.g., <i>AES</i>), and may be followed by a feedback mode and62* padding scheme.63*64* <p> A transformation is of the form:65*66* <ul>67* <li>"<i>algorithm/mode/padding</i>" or68*69* <li>"<i>algorithm</i>"70* </ul>71*72* <P> (in the latter case,73* provider-specific default values for the mode and padding scheme are used).74* For example, the following is a valid transformation:75*76* <pre>77* Cipher c = Cipher.getInstance("<i>AES/CBC/PKCS5Padding</i>");78* </pre>79*80* <p>A provider may supply a separate class for each combination81* of <i>algorithm/mode/padding</i>, or may decide to provide more generic82* classes representing sub-transformations corresponding to83* <i>algorithm</i> or <i>algorithm/mode</i> or <i>algorithm//padding</i>84* (note the double slashes),85* in which case the requested mode and/or padding are set automatically by86* the <code>getInstance</code> methods of <code>Cipher</code>, which invoke87* the {@link #engineSetMode(java.lang.String) engineSetMode} and88* {@link #engineSetPadding(java.lang.String) engineSetPadding}89* methods of the provider's subclass of <code>CipherSpi</code>.90*91* <p>A <code>Cipher</code> property in a provider master class may have one of92* the following formats:93*94* <ul>95*96* <li>97* <pre>98* // provider's subclass of "CipherSpi" implements "algName" with99* // pluggable mode and padding100* <code>Cipher.</code><i>algName</i>101* </pre>102*103* <li>104* <pre>105* // provider's subclass of "CipherSpi" implements "algName" in the106* // specified "mode", with pluggable padding107* <code>Cipher.</code><i>algName/mode</i>108* </pre>109*110* <li>111* <pre>112* // provider's subclass of "CipherSpi" implements "algName" with the113* // specified "padding", with pluggable mode114* <code>Cipher.</code><i>algName//padding</i>115* </pre>116*117* <li>118* <pre>119* // provider's subclass of "CipherSpi" implements "algName" with the120* // specified "mode" and "padding"121* <code>Cipher.</code><i>algName/mode/padding</i>122* </pre>123*124* </ul>125*126* <p>For example, a provider may supply a subclass of <code>CipherSpi</code>127* that implements <i>AES/ECB/PKCS5Padding</i>, one that implements128* <i>AES/CBC/PKCS5Padding</i>, one that implements129* <i>AES/CFB/PKCS5Padding</i>, and yet another one that implements130* <i>AES/OFB/PKCS5Padding</i>. That provider would have the following131* <code>Cipher</code> properties in its master class:132*133* <ul>134*135* <li>136* <pre>137* <code>Cipher.</code><i>AES/ECB/PKCS5Padding</i>138* </pre>139*140* <li>141* <pre>142* <code>Cipher.</code><i>AES/CBC/PKCS5Padding</i>143* </pre>144*145* <li>146* <pre>147* <code>Cipher.</code><i>AES/CFB/PKCS5Padding</i>148* </pre>149*150* <li>151* <pre>152* <code>Cipher.</code><i>AES/OFB/PKCS5Padding</i>153* </pre>154*155* </ul>156*157* <p>Another provider may implement a class for each of the above modes158* (i.e., one class for <i>ECB</i>, one for <i>CBC</i>, one for <i>CFB</i>,159* and one for <i>OFB</i>), one class for <i>PKCS5Padding</i>,160* and a generic <i>AES</i> class that subclasses from <code>CipherSpi</code>.161* That provider would have the following162* <code>Cipher</code> properties in its master class:163*164* <ul>165*166* <li>167* <pre>168* <code>Cipher.</code><i>AES</i>169* </pre>170*171* </ul>172*173* <p>The <code>getInstance</code> factory method of the <code>Cipher</code>174* engine class follows these rules in order to instantiate a provider's175* implementation of <code>CipherSpi</code> for a176* transformation of the form "<i>algorithm</i>":177*178* <ol>179* <li>180* Check if the provider has registered a subclass of <code>CipherSpi</code>181* for the specified "<i>algorithm</i>".182* <p>If the answer is YES, instantiate this183* class, for whose mode and padding scheme default values (as supplied by184* the provider) are used.185* <p>If the answer is NO, throw a <code>NoSuchAlgorithmException</code>186* exception.187* </ol>188*189* <p>The <code>getInstance</code> factory method of the <code>Cipher</code>190* engine class follows these rules in order to instantiate a provider's191* implementation of <code>CipherSpi</code> for a192* transformation of the form "<i>algorithm/mode/padding</i>":193*194* <ol>195* <li>196* Check if the provider has registered a subclass of <code>CipherSpi</code>197* for the specified "<i>algorithm/mode/padding</i>" transformation.198* <p>If the answer is YES, instantiate it.199* <p>If the answer is NO, go to the next step.200* <li>201* Check if the provider has registered a subclass of <code>CipherSpi</code>202* for the sub-transformation "<i>algorithm/mode</i>".203* <p>If the answer is YES, instantiate it, and call204* <code>engineSetPadding(<i>padding</i>)</code> on the new instance.205* <p>If the answer is NO, go to the next step.206* <li>207* Check if the provider has registered a subclass of <code>CipherSpi</code>208* for the sub-transformation "<i>algorithm//padding</i>" (note the double209* slashes).210* <p>If the answer is YES, instantiate it, and call211* <code>engineSetMode(<i>mode</i>)</code> on the new instance.212* <p>If the answer is NO, go to the next step.213* <li>214* Check if the provider has registered a subclass of <code>CipherSpi</code>215* for the sub-transformation "<i>algorithm</i>".216* <p>If the answer is YES, instantiate it, and call217* <code>engineSetMode(<i>mode</i>)</code> and218* <code>engineSetPadding(<i>padding</i>)</code> on the new instance.219* <p>If the answer is NO, throw a <code>NoSuchAlgorithmException</code>220* exception.221* </ol>222*223* @author Jan Luehe224* @see KeyGenerator225* @see SecretKey226* @since 1.4227*/228229public abstract class CipherSpi {230231/**232* Constructor for subclasses to call.233*/234public CipherSpi() {}235236/**237* Sets the mode of this cipher.238*239* @param mode the cipher mode240*241* @exception NoSuchAlgorithmException if the requested cipher mode does242* not exist243*/244protected abstract void engineSetMode(String mode)245throws NoSuchAlgorithmException;246247/**248* Sets the padding mechanism of this cipher.249*250* @param padding the padding mechanism251*252* @exception NoSuchPaddingException if the requested padding mechanism253* does not exist254*/255protected abstract void engineSetPadding(String padding)256throws NoSuchPaddingException;257258/**259* Returns the block size (in bytes).260*261* @return the block size (in bytes), or 0 if the underlying algorithm is262* not a block cipher263*/264protected abstract int engineGetBlockSize();265266/**267* Returns the length in bytes that an output buffer would268* need to be in order to hold the result of the next <code>update</code>269* or <code>doFinal</code> operation, given the input length270* <code>inputLen</code> (in bytes).271*272* <p>This call takes into account any unprocessed (buffered) data from a273* previous <code>update</code> call, padding, and AEAD tagging.274*275* <p>The actual output length of the next <code>update</code> or276* <code>doFinal</code> call may be smaller than the length returned by277* this method.278*279* @param inputLen the input length (in bytes)280*281* @return the required output buffer size (in bytes)282*/283protected abstract int engineGetOutputSize(int inputLen);284285/**286* Returns the initialization vector (IV) in a new buffer.287*288* <p> This is useful in the context of password-based encryption or289* decryption, where the IV is derived from a user-provided passphrase.290*291* @return the initialization vector in a new buffer, or null if the292* underlying algorithm does not use an IV, or if the IV has not yet293* been set.294*/295protected abstract byte[] engineGetIV();296297/**298* Returns the parameters used with this cipher.299*300* <p>The returned parameters may be the same that were used to initialize301* this cipher, or may contain a combination of default and random302* parameter values used by the underlying cipher implementation if this303* cipher requires algorithm parameters but was not initialized with any.304*305* @return the parameters used with this cipher, or null if this cipher306* does not use any parameters.307*/308protected abstract AlgorithmParameters engineGetParameters();309310/**311* Initializes this cipher with a key and a source312* of randomness.313*314* <p>The cipher is initialized for one of the following four operations:315* encryption, decryption, key wrapping or key unwrapping, depending on316* the value of <code>opmode</code>.317*318* <p>If this cipher requires any algorithm parameters that cannot be319* derived from the given <code>key</code>, the underlying cipher320* implementation is supposed to generate the required parameters itself321* (using provider-specific default or random values) if it is being322* initialized for encryption or key wrapping, and raise an323* <code>InvalidKeyException</code> if it is being324* initialized for decryption or key unwrapping.325* The generated parameters can be retrieved using326* {@link #engineGetParameters() engineGetParameters} or327* {@link #engineGetIV() engineGetIV} (if the parameter is an IV).328*329* <p>If this cipher requires algorithm parameters that cannot be330* derived from the input parameters, and there are no reasonable331* provider-specific default values, initialization will332* necessarily fail.333*334* <p>If this cipher (including its underlying feedback or padding scheme)335* requires any random bytes (e.g., for parameter generation), it will get336* them from <code>random</code>.337*338* <p>Note that when a Cipher object is initialized, it loses all339* previously-acquired state. In other words, initializing a Cipher is340* equivalent to creating a new instance of that Cipher and initializing341* it.342*343* @param opmode the operation mode of this cipher (this is one of344* the following:345* <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,346* <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)347* @param key the encryption key348* @param random the source of randomness349*350* @exception InvalidKeyException if the given key is inappropriate for351* initializing this cipher, or requires352* algorithm parameters that cannot be353* determined from the given key.354* @throws UnsupportedOperationException if {@code opmode} is355* {@code WRAP_MODE} or {@code UNWRAP_MODE} is not implemented356* by the cipher.357*/358protected abstract void engineInit(int opmode, Key key,359SecureRandom random)360throws InvalidKeyException;361362/**363* Initializes this cipher with a key, a set of364* algorithm parameters, and a source of randomness.365*366* <p>The cipher is initialized for one of the following four operations:367* encryption, decryption, key wrapping or key unwrapping, depending on368* the value of <code>opmode</code>.369*370* <p>If this cipher requires any algorithm parameters and371* <code>params</code> is null, the underlying cipher implementation is372* supposed to generate the required parameters itself (using373* provider-specific default or random values) if it is being374* initialized for encryption or key wrapping, and raise an375* <code>InvalidAlgorithmParameterException</code> if it is being376* initialized for decryption or key unwrapping.377* The generated parameters can be retrieved using378* {@link #engineGetParameters() engineGetParameters} or379* {@link #engineGetIV() engineGetIV} (if the parameter is an IV).380*381* <p>If this cipher requires algorithm parameters that cannot be382* derived from the input parameters, and there are no reasonable383* provider-specific default values, initialization will384* necessarily fail.385*386* <p>If this cipher (including its underlying feedback or padding scheme)387* requires any random bytes (e.g., for parameter generation), it will get388* them from <code>random</code>.389*390* <p>Note that when a Cipher object is initialized, it loses all391* previously-acquired state. In other words, initializing a Cipher is392* equivalent to creating a new instance of that Cipher and initializing393* it.394*395* @param opmode the operation mode of this cipher (this is one of396* the following:397* <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,398* <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)399* @param key the encryption key400* @param params the algorithm parameters401* @param random the source of randomness402*403* @exception InvalidKeyException if the given key is inappropriate for404* initializing this cipher405* @exception InvalidAlgorithmParameterException if the given algorithm406* parameters are inappropriate for this cipher,407* or if this cipher requires408* algorithm parameters and <code>params</code> is null.409* @throws UnsupportedOperationException if {@code opmode} is410* {@code WRAP_MODE} or {@code UNWRAP_MODE} is not implemented411* by the cipher.412*/413protected abstract void engineInit(int opmode, Key key,414AlgorithmParameterSpec params,415SecureRandom random)416throws InvalidKeyException, InvalidAlgorithmParameterException;417418/**419* Initializes this cipher with a key, a set of420* algorithm parameters, and a source of randomness.421*422* <p>The cipher is initialized for one of the following four operations:423* encryption, decryption, key wrapping or key unwrapping, depending on424* the value of <code>opmode</code>.425*426* <p>If this cipher requires any algorithm parameters and427* <code>params</code> is null, the underlying cipher implementation is428* supposed to generate the required parameters itself (using429* provider-specific default or random values) if it is being430* initialized for encryption or key wrapping, and raise an431* <code>InvalidAlgorithmParameterException</code> if it is being432* initialized for decryption or key unwrapping.433* The generated parameters can be retrieved using434* {@link #engineGetParameters() engineGetParameters} or435* {@link #engineGetIV() engineGetIV} (if the parameter is an IV).436*437* <p>If this cipher requires algorithm parameters that cannot be438* derived from the input parameters, and there are no reasonable439* provider-specific default values, initialization will440* necessarily fail.441*442* <p>If this cipher (including its underlying feedback or padding scheme)443* requires any random bytes (e.g., for parameter generation), it will get444* them from <code>random</code>.445*446* <p>Note that when a Cipher object is initialized, it loses all447* previously-acquired state. In other words, initializing a Cipher is448* equivalent to creating a new instance of that Cipher and initializing449* it.450*451* @param opmode the operation mode of this cipher (this is one of452* the following:453* <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,454* <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)455* @param key the encryption key456* @param params the algorithm parameters457* @param random the source of randomness458*459* @exception InvalidKeyException if the given key is inappropriate for460* initializing this cipher461* @exception InvalidAlgorithmParameterException if the given algorithm462* parameters are inappropriate for this cipher,463* or if this cipher requires464* algorithm parameters and <code>params</code> is null.465* @throws UnsupportedOperationException if {@code opmode} is466* {@code WRAP_MODE} or {@code UNWRAP_MODE} is not implemented467* by the cipher.468*/469protected abstract void engineInit(int opmode, Key key,470AlgorithmParameters params,471SecureRandom random)472throws InvalidKeyException, InvalidAlgorithmParameterException;473474/**475* Continues a multiple-part encryption or decryption operation476* (depending on how this cipher was initialized), processing another data477* part.478*479* <p>The first <code>inputLen</code> bytes in the <code>input</code>480* buffer, starting at <code>inputOffset</code> inclusive, are processed,481* and the result is stored in a new buffer.482*483* @param input the input buffer484* @param inputOffset the offset in <code>input</code> where the input485* starts486* @param inputLen the input length487*488* @return the new buffer with the result, or null if the underlying489* cipher is a block cipher and the input data is too short to result in a490* new block.491*/492protected abstract byte[] engineUpdate(byte[] input, int inputOffset,493int inputLen);494495/**496* Continues a multiple-part encryption or decryption operation497* (depending on how this cipher was initialized), processing another data498* part.499*500* <p>The first <code>inputLen</code> bytes in the <code>input</code>501* buffer, starting at <code>inputOffset</code> inclusive, are processed,502* and the result is stored in the <code>output</code> buffer, starting at503* <code>outputOffset</code> inclusive.504*505* <p>If the <code>output</code> buffer is too small to hold the result,506* a <code>ShortBufferException</code> is thrown.507*508* @param input the input buffer509* @param inputOffset the offset in <code>input</code> where the input510* starts511* @param inputLen the input length512* @param output the buffer for the result513* @param outputOffset the offset in <code>output</code> where the result514* is stored515*516* @return the number of bytes stored in <code>output</code>517*518* @exception ShortBufferException if the given output buffer is too small519* to hold the result520*/521protected abstract int engineUpdate(byte[] input, int inputOffset,522int inputLen, byte[] output,523int outputOffset)524throws ShortBufferException;525526/**527* Continues a multiple-part encryption or decryption operation528* (depending on how this cipher was initialized), processing another data529* part.530*531* <p>All <code>input.remaining()</code> bytes starting at532* <code>input.position()</code> are processed. The result is stored533* in the output buffer.534* Upon return, the input buffer's position will be equal535* to its limit; its limit will not have changed. The output buffer's536* position will have advanced by n, where n is the value returned537* by this method; the output buffer's limit will not have changed.538*539* <p>If <code>output.remaining()</code> bytes are insufficient to540* hold the result, a <code>ShortBufferException</code> is thrown.541*542* <p>Subclasses should consider overriding this method if they can543* process ByteBuffers more efficiently than byte arrays.544*545* @param input the input ByteBuffer546* @param output the output ByteByffer547*548* @return the number of bytes stored in <code>output</code>549*550* @exception ShortBufferException if there is insufficient space in the551* output buffer552*553* @throws NullPointerException if either parameter is <CODE>null</CODE>554* @since 1.5555*/556protected int engineUpdate(ByteBuffer input, ByteBuffer output)557throws ShortBufferException {558try {559return bufferCrypt(input, output, true);560} catch (IllegalBlockSizeException e) {561// never thrown for engineUpdate()562throw new ProviderException("Internal error in update()");563} catch (BadPaddingException e) {564// never thrown for engineUpdate()565throw new ProviderException("Internal error in update()");566}567}568569/**570* Encrypts or decrypts data in a single-part operation,571* or finishes a multiple-part operation.572* The data is encrypted or decrypted, depending on how this cipher was573* initialized.574*575* <p>The first <code>inputLen</code> bytes in the <code>input</code>576* buffer, starting at <code>inputOffset</code> inclusive, and any input577* bytes that may have been buffered during a previous <code>update</code>578* operation, are processed, with padding (if requested) being applied.579* If an AEAD mode such as GCM/CCM is being used, the authentication580* tag is appended in the case of encryption, or verified in the581* case of decryption.582* The result is stored in a new buffer.583*584* <p>Upon finishing, this method resets this cipher object to the state585* it was in when previously initialized via a call to586* <code>engineInit</code>.587* That is, the object is reset and available to encrypt or decrypt588* (depending on the operation mode that was specified in the call to589* <code>engineInit</code>) more data.590*591* <p>Note: if any exception is thrown, this cipher object may need to592* be reset before it can be used again.593*594* @param input the input buffer595* @param inputOffset the offset in <code>input</code> where the input596* starts597* @param inputLen the input length598*599* @return the new buffer with the result600*601* @exception IllegalBlockSizeException if this cipher is a block cipher,602* no padding has been requested (only in encryption mode), and the total603* input length of the data processed by this cipher is not a multiple of604* block size; or if this encryption algorithm is unable to605* process the input data provided.606* @exception BadPaddingException if this cipher is in decryption mode,607* and (un)padding has been requested, but the decrypted data is not608* bounded by the appropriate padding bytes609* @exception AEADBadTagException if this cipher is decrypting in an610* AEAD mode (such as GCM/CCM), and the received authentication tag611* does not match the calculated value612*/613protected abstract byte[] engineDoFinal(byte[] input, int inputOffset,614int inputLen)615throws IllegalBlockSizeException, BadPaddingException;616617/**618* Encrypts or decrypts data in a single-part operation,619* or finishes a multiple-part operation.620* The data is encrypted or decrypted, depending on how this cipher was621* initialized.622*623* <p>The first <code>inputLen</code> bytes in the <code>input</code>624* buffer, starting at <code>inputOffset</code> inclusive, and any input625* bytes that may have been buffered during a previous <code>update</code>626* operation, are processed, with padding (if requested) being applied.627* If an AEAD mode such as GCM/CCM is being used, the authentication628* tag is appended in the case of encryption, or verified in the629* case of decryption.630* The result is stored in the <code>output</code> buffer, starting at631* <code>outputOffset</code> inclusive.632*633* <p>If the <code>output</code> buffer is too small to hold the result,634* a <code>ShortBufferException</code> is thrown.635*636* <p>Upon finishing, this method resets this cipher object to the state637* it was in when previously initialized via a call to638* <code>engineInit</code>.639* That is, the object is reset and available to encrypt or decrypt640* (depending on the operation mode that was specified in the call to641* <code>engineInit</code>) more data.642*643* <p>Note: if any exception is thrown, this cipher object may need to644* be reset before it can be used again.645*646* @param input the input buffer647* @param inputOffset the offset in <code>input</code> where the input648* starts649* @param inputLen the input length650* @param output the buffer for the result651* @param outputOffset the offset in <code>output</code> where the result652* is stored653*654* @return the number of bytes stored in <code>output</code>655*656* @exception IllegalBlockSizeException if this cipher is a block cipher,657* no padding has been requested (only in encryption mode), and the total658* input length of the data processed by this cipher is not a multiple of659* block size; or if this encryption algorithm is unable to660* process the input data provided.661* @exception ShortBufferException if the given output buffer is too small662* to hold the result663* @exception BadPaddingException if this cipher is in decryption mode,664* and (un)padding has been requested, but the decrypted data is not665* bounded by the appropriate padding bytes666* @exception AEADBadTagException if this cipher is decrypting in an667* AEAD mode (such as GCM/CCM), and the received authentication tag668* does not match the calculated value669*/670protected abstract int engineDoFinal(byte[] input, int inputOffset,671int inputLen, byte[] output,672int outputOffset)673throws ShortBufferException, IllegalBlockSizeException,674BadPaddingException;675676/**677* Encrypts or decrypts data in a single-part operation,678* or finishes a multiple-part operation.679* The data is encrypted or decrypted, depending on how this cipher was680* initialized.681*682* <p>All <code>input.remaining()</code> bytes starting at683* <code>input.position()</code> are processed.684* If an AEAD mode such as GCM/CCM is being used, the authentication685* tag is appended in the case of encryption, or verified in the686* case of decryption.687* The result is stored in the output buffer.688* Upon return, the input buffer's position will be equal689* to its limit; its limit will not have changed. The output buffer's690* position will have advanced by n, where n is the value returned691* by this method; the output buffer's limit will not have changed.692*693* <p>If <code>output.remaining()</code> bytes are insufficient to694* hold the result, a <code>ShortBufferException</code> is thrown.695*696* <p>Upon finishing, this method resets this cipher object to the state697* it was in when previously initialized via a call to698* <code>engineInit</code>.699* That is, the object is reset and available to encrypt or decrypt700* (depending on the operation mode that was specified in the call to701* <code>engineInit</code>) more data.702*703* <p>Note: if any exception is thrown, this cipher object may need to704* be reset before it can be used again.705*706* <p>Subclasses should consider overriding this method if they can707* process ByteBuffers more efficiently than byte arrays.708*709* @param input the input ByteBuffer710* @param output the output ByteByffer711*712* @return the number of bytes stored in <code>output</code>713*714* @exception IllegalBlockSizeException if this cipher is a block cipher,715* no padding has been requested (only in encryption mode), and the total716* input length of the data processed by this cipher is not a multiple of717* block size; or if this encryption algorithm is unable to718* process the input data provided.719* @exception ShortBufferException if there is insufficient space in the720* output buffer721* @exception BadPaddingException if this cipher is in decryption mode,722* and (un)padding has been requested, but the decrypted data is not723* bounded by the appropriate padding bytes724* @exception AEADBadTagException if this cipher is decrypting in an725* AEAD mode (such as GCM/CCM), and the received authentication tag726* does not match the calculated value727*728* @throws NullPointerException if either parameter is <CODE>null</CODE>729* @since 1.5730*/731protected int engineDoFinal(ByteBuffer input, ByteBuffer output)732throws ShortBufferException, IllegalBlockSizeException,733BadPaddingException {734return bufferCrypt(input, output, false);735}736737// copied from sun.security.jca.JCAUtil738// will be changed to reference that method once that code has been739// integrated and promoted740static int getTempArraySize(int totalSize) {741return Math.min(4096, totalSize);742}743744/**745* Implementation for encryption using ByteBuffers. Used for both746* engineUpdate() and engineDoFinal().747*/748private int bufferCrypt(ByteBuffer input, ByteBuffer output,749boolean isUpdate) throws ShortBufferException,750IllegalBlockSizeException, BadPaddingException {751if ((input == null) || (output == null)) {752throw new NullPointerException753("Input and output buffers must not be null");754}755int inPos = input.position();756int inLimit = input.limit();757int inLen = inLimit - inPos;758if (isUpdate && (inLen == 0)) {759return 0;760}761int outLenNeeded = engineGetOutputSize(inLen);762763if (output.remaining() < outLenNeeded) {764throw new ShortBufferException("Need at least " + outLenNeeded765+ " bytes of space in output buffer");766}767768// detecting input and output buffer overlap may be tricky769// we can only write directly into output buffer when we770// are 100% sure it's safe to do so771772boolean a1 = input.hasArray();773boolean a2 = output.hasArray();774int total = 0;775776if (a1) { // input has an accessible byte[]777byte[] inArray = input.array();778int inOfs = input.arrayOffset() + inPos;779780if (a2) { // output has an accessible byte[]781byte[] outArray = output.array();782int outPos = output.position();783int outOfs = output.arrayOffset() + outPos;784785// check array address and offsets and use temp output buffer786// if output offset is larger than input offset and787// falls within the range of input data788boolean useTempOut = false;789if (inArray == outArray &&790((inOfs < outOfs) && (outOfs < inOfs + inLen))) {791useTempOut = true;792outArray = new byte[outLenNeeded];793outOfs = 0;794}795if (isUpdate) {796total = engineUpdate(inArray, inOfs, inLen, outArray, outOfs);797} else {798total = engineDoFinal(inArray, inOfs, inLen, outArray, outOfs);799}800if (useTempOut) {801output.put(outArray, outOfs, total);802} else {803// adjust output position manually804output.position(outPos + total);805}806// adjust input position manually807input.position(inLimit);808} else { // output does not have an accessible byte[]809byte[] outArray = null;810if (isUpdate) {811outArray = engineUpdate(inArray, inOfs, inLen);812} else {813outArray = engineDoFinal(inArray, inOfs, inLen);814}815if (outArray != null && outArray.length != 0) {816output.put(outArray);817total = outArray.length;818}819// adjust input position manually820input.position(inLimit);821}822} else { // input does not have an accessible byte[]823// have to assume the worst, since we have no way of determine824// if input and output overlaps or not825byte[] tempOut = new byte[outLenNeeded];826int outOfs = 0;827828byte[] tempIn = new byte[getTempArraySize(inLen)];829do {830int chunk = Math.min(inLen, tempIn.length);831if (chunk > 0) {832input.get(tempIn, 0, chunk);833}834int n;835if (isUpdate || (inLen > chunk)) {836n = engineUpdate(tempIn, 0, chunk, tempOut, outOfs);837} else {838n = engineDoFinal(tempIn, 0, chunk, tempOut, outOfs);839}840outOfs += n;841total += n;842inLen -= chunk;843} while (inLen > 0);844if (total > 0) {845output.put(tempOut, 0, total);846}847}848849return total;850}851852/**853* Wrap a key.854*855* <p>This concrete method has been added to this previously-defined856* abstract class. (For backwards compatibility, it cannot be abstract.)857* It may be overridden by a provider to wrap a key.858* Such an override is expected to throw an IllegalBlockSizeException or859* InvalidKeyException (under the specified circumstances),860* if the given key cannot be wrapped.861* If this method is not overridden, it always throws an862* UnsupportedOperationException.863*864* @param key the key to be wrapped.865*866* @return the wrapped key.867*868* @exception IllegalBlockSizeException if this cipher is a block cipher,869* no padding has been requested, and the length of the encoding of the870* key to be wrapped is not a multiple of the block size.871*872* @exception InvalidKeyException if it is impossible or unsafe to873* wrap the key with this cipher (e.g., a hardware protected key is874* being passed to a software-only cipher).875*876* @throws UnsupportedOperationException if this method is not supported.877*/878protected byte[] engineWrap(Key key)879throws IllegalBlockSizeException, InvalidKeyException880{881throw new UnsupportedOperationException();882}883884/**885* Unwrap a previously wrapped key.886*887* <p>This concrete method has been added to this previously-defined888* abstract class. (For backwards compatibility, it cannot be abstract.)889* It may be overridden by a provider to unwrap a previously wrapped key.890* Such an override is expected to throw an InvalidKeyException if891* the given wrapped key cannot be unwrapped.892* If this method is not overridden, it always throws an893* UnsupportedOperationException.894*895* @param wrappedKey the key to be unwrapped.896*897* @param wrappedKeyAlgorithm the algorithm associated with the wrapped898* key.899*900* @param wrappedKeyType the type of the wrapped key. This is one of901* <code>SECRET_KEY</code>, <code>PRIVATE_KEY</code>, or902* <code>PUBLIC_KEY</code>.903*904* @return the unwrapped key.905*906* @exception NoSuchAlgorithmException if no installed providers907* can create keys of type <code>wrappedKeyType</code> for the908* <code>wrappedKeyAlgorithm</code>.909*910* @exception InvalidKeyException if <code>wrappedKey</code> does not911* represent a wrapped key of type <code>wrappedKeyType</code> for912* the <code>wrappedKeyAlgorithm</code>.913*914* @throws UnsupportedOperationException if this method is not supported.915*/916protected Key engineUnwrap(byte[] wrappedKey,917String wrappedKeyAlgorithm,918int wrappedKeyType)919throws InvalidKeyException, NoSuchAlgorithmException920{921throw new UnsupportedOperationException();922}923924/**925* Returns the key size of the given key object in bits.926* <p>This concrete method has been added to this previously-defined927* abstract class. It throws an <code>UnsupportedOperationException</code>928* if it is not overridden by the provider.929*930* @param key the key object.931*932* @return the key size of the given key object.933*934* @exception InvalidKeyException if <code>key</code> is invalid.935*/936protected int engineGetKeySize(Key key)937throws InvalidKeyException938{939throw new UnsupportedOperationException();940}941942/**943* Continues a multi-part update of the Additional Authentication944* Data (AAD), using a subset of the provided buffer.945* <p>946* Calls to this method provide AAD to the cipher when operating in947* modes such as AEAD (GCM/CCM). If this cipher is operating in948* either GCM or CCM mode, all AAD must be supplied before beginning949* operations on the ciphertext (via the {@code update} and {@code950* doFinal} methods).951*952* @param src the buffer containing the AAD953* @param offset the offset in {@code src} where the AAD input starts954* @param len the number of AAD bytes955*956* @throws IllegalStateException if this cipher is in a wrong state957* (e.g., has not been initialized), does not accept AAD, or if958* operating in either GCM or CCM mode and one of the {@code update}959* methods has already been called for the active960* encryption/decryption operation961* @throws UnsupportedOperationException if this method962* has not been overridden by an implementation963*964* @since 1.7965*/966protected void engineUpdateAAD(byte[] src, int offset, int len) {967throw new UnsupportedOperationException(968"The underlying Cipher implementation "969+ "does not support this method");970}971972/**973* Continues a multi-part update of the Additional Authentication974* Data (AAD).975* <p>976* Calls to this method provide AAD to the cipher when operating in977* modes such as AEAD (GCM/CCM). If this cipher is operating in978* either GCM or CCM mode, all AAD must be supplied before beginning979* operations on the ciphertext (via the {@code update} and {@code980* doFinal} methods).981* <p>982* All {@code src.remaining()} bytes starting at983* {@code src.position()} are processed.984* Upon return, the input buffer's position will be equal985* to its limit; its limit will not have changed.986*987* @param src the buffer containing the AAD988*989* @throws IllegalStateException if this cipher is in a wrong state990* (e.g., has not been initialized), does not accept AAD, or if991* operating in either GCM or CCM mode and one of the {@code update}992* methods has already been called for the active993* encryption/decryption operation994* @throws UnsupportedOperationException if this method995* has not been overridden by an implementation996*997* @since 1.7998*/999protected void engineUpdateAAD(ByteBuffer src) {1000throw new UnsupportedOperationException(1001"The underlying Cipher implementation "1002+ "does not support this method");1003}1004}100510061007