Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/crypto/CipherSpi.java
38829 views
/*1* Copyright (c) 1997, 2018, 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* Sets the mode of this cipher.233*234* @param mode the cipher mode235*236* @exception NoSuchAlgorithmException if the requested cipher mode does237* not exist238*/239protected abstract void engineSetMode(String mode)240throws NoSuchAlgorithmException;241242/**243* Sets the padding mechanism of this cipher.244*245* @param padding the padding mechanism246*247* @exception NoSuchPaddingException if the requested padding mechanism248* does not exist249*/250protected abstract void engineSetPadding(String padding)251throws NoSuchPaddingException;252253/**254* Returns the block size (in bytes).255*256* @return the block size (in bytes), or 0 if the underlying algorithm is257* not a block cipher258*/259protected abstract int engineGetBlockSize();260261/**262* Returns the length in bytes that an output buffer would263* need to be in order to hold the result of the next <code>update</code>264* or <code>doFinal</code> operation, given the input length265* <code>inputLen</code> (in bytes).266*267* <p>This call takes into account any unprocessed (buffered) data from a268* previous <code>update</code> call, padding, and AEAD tagging.269*270* <p>The actual output length of the next <code>update</code> or271* <code>doFinal</code> call may be smaller than the length returned by272* this method.273*274* @param inputLen the input length (in bytes)275*276* @return the required output buffer size (in bytes)277*/278protected abstract int engineGetOutputSize(int inputLen);279280/**281* Returns the initialization vector (IV) in a new buffer.282*283* <p> This is useful in the context of password-based encryption or284* decryption, where the IV is derived from a user-provided passphrase.285*286* @return the initialization vector in a new buffer, or null if the287* underlying algorithm does not use an IV, or if the IV has not yet288* been set.289*/290protected abstract byte[] engineGetIV();291292/**293* Returns the parameters used with this cipher.294*295* <p>The returned parameters may be the same that were used to initialize296* this cipher, or may contain a combination of default and random297* parameter values used by the underlying cipher implementation if this298* cipher requires algorithm parameters but was not initialized with any.299*300* @return the parameters used with this cipher, or null if this cipher301* does not use any parameters.302*/303protected abstract AlgorithmParameters engineGetParameters();304305/**306* Initializes this cipher with a key and a source307* of randomness.308*309* <p>The cipher is initialized for one of the following four operations:310* encryption, decryption, key wrapping or key unwrapping, depending on311* the value of <code>opmode</code>.312*313* <p>If this cipher requires any algorithm parameters that cannot be314* derived from the given <code>key</code>, the underlying cipher315* implementation is supposed to generate the required parameters itself316* (using provider-specific default or random values) if it is being317* initialized for encryption or key wrapping, and raise an318* <code>InvalidKeyException</code> if it is being319* initialized for decryption or key unwrapping.320* The generated parameters can be retrieved using321* {@link #engineGetParameters() engineGetParameters} or322* {@link #engineGetIV() engineGetIV} (if the parameter is an IV).323*324* <p>If this cipher requires algorithm parameters that cannot be325* derived from the input parameters, and there are no reasonable326* provider-specific default values, initialization will327* necessarily fail.328*329* <p>If this cipher (including its underlying feedback or padding scheme)330* requires any random bytes (e.g., for parameter generation), it will get331* them from <code>random</code>.332*333* <p>Note that when a Cipher object is initialized, it loses all334* previously-acquired state. In other words, initializing a Cipher is335* equivalent to creating a new instance of that Cipher and initializing336* it.337*338* @param opmode the operation mode of this cipher (this is one of339* the following:340* <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,341* <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)342* @param key the encryption key343* @param random the source of randomness344*345* @exception InvalidKeyException if the given key is inappropriate for346* initializing this cipher, or requires347* algorithm parameters that cannot be348* determined from the given key.349* @throws UnsupportedOperationException if {@code opmode} is350* {@code WRAP_MODE} or {@code UNWRAP_MODE} is not implemented351* by the cipher.352*/353protected abstract void engineInit(int opmode, Key key,354SecureRandom random)355throws InvalidKeyException;356357/**358* Initializes this cipher with a key, a set of359* algorithm parameters, and a source of randomness.360*361* <p>The cipher is initialized for one of the following four operations:362* encryption, decryption, key wrapping or key unwrapping, depending on363* the value of <code>opmode</code>.364*365* <p>If this cipher requires any algorithm parameters and366* <code>params</code> is null, the underlying cipher implementation is367* supposed to generate the required parameters itself (using368* provider-specific default or random values) if it is being369* initialized for encryption or key wrapping, and raise an370* <code>InvalidAlgorithmParameterException</code> if it is being371* initialized for decryption or key unwrapping.372* The generated parameters can be retrieved using373* {@link #engineGetParameters() engineGetParameters} or374* {@link #engineGetIV() engineGetIV} (if the parameter is an IV).375*376* <p>If this cipher requires algorithm parameters that cannot be377* derived from the input parameters, and there are no reasonable378* provider-specific default values, initialization will379* necessarily fail.380*381* <p>If this cipher (including its underlying feedback or padding scheme)382* requires any random bytes (e.g., for parameter generation), it will get383* them from <code>random</code>.384*385* <p>Note that when a Cipher object is initialized, it loses all386* previously-acquired state. In other words, initializing a Cipher is387* equivalent to creating a new instance of that Cipher and initializing388* it.389*390* @param opmode the operation mode of this cipher (this is one of391* the following:392* <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,393* <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)394* @param key the encryption key395* @param params the algorithm parameters396* @param random the source of randomness397*398* @exception InvalidKeyException if the given key is inappropriate for399* initializing this cipher400* @exception InvalidAlgorithmParameterException if the given algorithm401* parameters are inappropriate for this cipher,402* or if this cipher requires403* algorithm parameters and <code>params</code> is null.404* @throws UnsupportedOperationException if {@code opmode} is405* {@code WRAP_MODE} or {@code UNWRAP_MODE} is not implemented406* by the cipher.407*/408protected abstract void engineInit(int opmode, Key key,409AlgorithmParameterSpec params,410SecureRandom random)411throws InvalidKeyException, InvalidAlgorithmParameterException;412413/**414* Initializes this cipher with a key, a set of415* algorithm parameters, and a source of randomness.416*417* <p>The cipher is initialized for one of the following four operations:418* encryption, decryption, key wrapping or key unwrapping, depending on419* the value of <code>opmode</code>.420*421* <p>If this cipher requires any algorithm parameters and422* <code>params</code> is null, the underlying cipher implementation is423* supposed to generate the required parameters itself (using424* provider-specific default or random values) if it is being425* initialized for encryption or key wrapping, and raise an426* <code>InvalidAlgorithmParameterException</code> if it is being427* initialized for decryption or key unwrapping.428* The generated parameters can be retrieved using429* {@link #engineGetParameters() engineGetParameters} or430* {@link #engineGetIV() engineGetIV} (if the parameter is an IV).431*432* <p>If this cipher requires algorithm parameters that cannot be433* derived from the input parameters, and there are no reasonable434* provider-specific default values, initialization will435* necessarily fail.436*437* <p>If this cipher (including its underlying feedback or padding scheme)438* requires any random bytes (e.g., for parameter generation), it will get439* them from <code>random</code>.440*441* <p>Note that when a Cipher object is initialized, it loses all442* previously-acquired state. In other words, initializing a Cipher is443* equivalent to creating a new instance of that Cipher and initializing444* it.445*446* @param opmode the operation mode of this cipher (this is one of447* the following:448* <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,449* <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)450* @param key the encryption key451* @param params the algorithm parameters452* @param random the source of randomness453*454* @exception InvalidKeyException if the given key is inappropriate for455* initializing this cipher456* @exception InvalidAlgorithmParameterException if the given algorithm457* parameters are inappropriate for this cipher,458* or if this cipher requires459* algorithm parameters and <code>params</code> is null.460* @throws UnsupportedOperationException if {@code opmode} is461* {@code WRAP_MODE} or {@code UNWRAP_MODE} is not implemented462* by the cipher.463*/464protected abstract void engineInit(int opmode, Key key,465AlgorithmParameters params,466SecureRandom random)467throws InvalidKeyException, InvalidAlgorithmParameterException;468469/**470* Continues a multiple-part encryption or decryption operation471* (depending on how this cipher was initialized), processing another data472* part.473*474* <p>The first <code>inputLen</code> bytes in the <code>input</code>475* buffer, starting at <code>inputOffset</code> inclusive, are processed,476* and the result is stored in a new buffer.477*478* @param input the input buffer479* @param inputOffset the offset in <code>input</code> where the input480* starts481* @param inputLen the input length482*483* @return the new buffer with the result, or null if the underlying484* cipher is a block cipher and the input data is too short to result in a485* new block.486*/487protected abstract byte[] engineUpdate(byte[] input, int inputOffset,488int inputLen);489490/**491* Continues a multiple-part encryption or decryption operation492* (depending on how this cipher was initialized), processing another data493* part.494*495* <p>The first <code>inputLen</code> bytes in the <code>input</code>496* buffer, starting at <code>inputOffset</code> inclusive, are processed,497* and the result is stored in the <code>output</code> buffer, starting at498* <code>outputOffset</code> inclusive.499*500* <p>If the <code>output</code> buffer is too small to hold the result,501* a <code>ShortBufferException</code> is thrown.502*503* @param input the input buffer504* @param inputOffset the offset in <code>input</code> where the input505* starts506* @param inputLen the input length507* @param output the buffer for the result508* @param outputOffset the offset in <code>output</code> where the result509* is stored510*511* @return the number of bytes stored in <code>output</code>512*513* @exception ShortBufferException if the given output buffer is too small514* to hold the result515*/516protected abstract int engineUpdate(byte[] input, int inputOffset,517int inputLen, byte[] output,518int outputOffset)519throws ShortBufferException;520521/**522* Continues a multiple-part encryption or decryption operation523* (depending on how this cipher was initialized), processing another data524* part.525*526* <p>All <code>input.remaining()</code> bytes starting at527* <code>input.position()</code> are processed. The result is stored528* in the output buffer.529* Upon return, the input buffer's position will be equal530* to its limit; its limit will not have changed. The output buffer's531* position will have advanced by n, where n is the value returned532* by this method; the output buffer's limit will not have changed.533*534* <p>If <code>output.remaining()</code> bytes are insufficient to535* hold the result, a <code>ShortBufferException</code> is thrown.536*537* <p>Subclasses should consider overriding this method if they can538* process ByteBuffers more efficiently than byte arrays.539*540* @param input the input ByteBuffer541* @param output the output ByteByffer542*543* @return the number of bytes stored in <code>output</code>544*545* @exception ShortBufferException if there is insufficient space in the546* output buffer547*548* @throws NullPointerException if either parameter is <CODE>null</CODE>549* @since 1.5550*/551protected int engineUpdate(ByteBuffer input, ByteBuffer output)552throws ShortBufferException {553try {554return bufferCrypt(input, output, true);555} catch (IllegalBlockSizeException e) {556// never thrown for engineUpdate()557throw new ProviderException("Internal error in update()");558} catch (BadPaddingException e) {559// never thrown for engineUpdate()560throw new ProviderException("Internal error in update()");561}562}563564/**565* Encrypts or decrypts data in a single-part operation,566* or finishes a multiple-part operation.567* The data is encrypted or decrypted, depending on how this cipher was568* initialized.569*570* <p>The first <code>inputLen</code> bytes in the <code>input</code>571* buffer, starting at <code>inputOffset</code> inclusive, and any input572* bytes that may have been buffered during a previous <code>update</code>573* operation, are processed, with padding (if requested) being applied.574* If an AEAD mode such as GCM/CCM is being used, the authentication575* tag is appended in the case of encryption, or verified in the576* case of decryption.577* The result is stored in a new buffer.578*579* <p>Upon finishing, this method resets this cipher object to the state580* it was in when previously initialized via a call to581* <code>engineInit</code>.582* That is, the object is reset and available to encrypt or decrypt583* (depending on the operation mode that was specified in the call to584* <code>engineInit</code>) more data.585*586* <p>Note: if any exception is thrown, this cipher object may need to587* be reset before it can be used again.588*589* @param input the input buffer590* @param inputOffset the offset in <code>input</code> where the input591* starts592* @param inputLen the input length593*594* @return the new buffer with the result595*596* @exception IllegalBlockSizeException if this cipher is a block cipher,597* no padding has been requested (only in encryption mode), and the total598* input length of the data processed by this cipher is not a multiple of599* block size; or if this encryption algorithm is unable to600* process the input data provided.601* @exception BadPaddingException if this cipher is in decryption mode,602* and (un)padding has been requested, but the decrypted data is not603* bounded by the appropriate padding bytes604* @exception AEADBadTagException if this cipher is decrypting in an605* AEAD mode (such as GCM/CCM), and the received authentication tag606* does not match the calculated value607*/608protected abstract byte[] engineDoFinal(byte[] input, int inputOffset,609int inputLen)610throws IllegalBlockSizeException, BadPaddingException;611612/**613* Encrypts or decrypts data in a single-part operation,614* or finishes a multiple-part operation.615* The data is encrypted or decrypted, depending on how this cipher was616* initialized.617*618* <p>The first <code>inputLen</code> bytes in the <code>input</code>619* buffer, starting at <code>inputOffset</code> inclusive, and any input620* bytes that may have been buffered during a previous <code>update</code>621* operation, are processed, with padding (if requested) being applied.622* If an AEAD mode such as GCM/CCM is being used, the authentication623* tag is appended in the case of encryption, or verified in the624* case of decryption.625* The result is stored in the <code>output</code> buffer, starting at626* <code>outputOffset</code> inclusive.627*628* <p>If the <code>output</code> buffer is too small to hold the result,629* a <code>ShortBufferException</code> is thrown.630*631* <p>Upon finishing, this method resets this cipher object to the state632* it was in when previously initialized via a call to633* <code>engineInit</code>.634* That is, the object is reset and available to encrypt or decrypt635* (depending on the operation mode that was specified in the call to636* <code>engineInit</code>) more data.637*638* <p>Note: if any exception is thrown, this cipher object may need to639* be reset before it can be used again.640*641* @param input the input buffer642* @param inputOffset the offset in <code>input</code> where the input643* starts644* @param inputLen the input length645* @param output the buffer for the result646* @param outputOffset the offset in <code>output</code> where the result647* is stored648*649* @return the number of bytes stored in <code>output</code>650*651* @exception IllegalBlockSizeException if this cipher is a block cipher,652* no padding has been requested (only in encryption mode), and the total653* input length of the data processed by this cipher is not a multiple of654* block size; or if this encryption algorithm is unable to655* process the input data provided.656* @exception ShortBufferException if the given output buffer is too small657* to hold the result658* @exception BadPaddingException if this cipher is in decryption mode,659* and (un)padding has been requested, but the decrypted data is not660* bounded by the appropriate padding bytes661* @exception AEADBadTagException if this cipher is decrypting in an662* AEAD mode (such as GCM/CCM), and the received authentication tag663* does not match the calculated value664*/665protected abstract int engineDoFinal(byte[] input, int inputOffset,666int inputLen, byte[] output,667int outputOffset)668throws ShortBufferException, IllegalBlockSizeException,669BadPaddingException;670671/**672* Encrypts or decrypts data in a single-part operation,673* or finishes a multiple-part operation.674* The data is encrypted or decrypted, depending on how this cipher was675* initialized.676*677* <p>All <code>input.remaining()</code> bytes starting at678* <code>input.position()</code> are processed.679* If an AEAD mode such as GCM/CCM is being used, the authentication680* tag is appended in the case of encryption, or verified in the681* case of decryption.682* The result is stored in the output buffer.683* Upon return, the input buffer's position will be equal684* to its limit; its limit will not have changed. The output buffer's685* position will have advanced by n, where n is the value returned686* by this method; the output buffer's limit will not have changed.687*688* <p>If <code>output.remaining()</code> bytes are insufficient to689* hold the result, a <code>ShortBufferException</code> is thrown.690*691* <p>Upon finishing, this method resets this cipher object to the state692* it was in when previously initialized via a call to693* <code>engineInit</code>.694* That is, the object is reset and available to encrypt or decrypt695* (depending on the operation mode that was specified in the call to696* <code>engineInit</code>) more data.697*698* <p>Note: if any exception is thrown, this cipher object may need to699* be reset before it can be used again.700*701* <p>Subclasses should consider overriding this method if they can702* process ByteBuffers more efficiently than byte arrays.703*704* @param input the input ByteBuffer705* @param output the output ByteByffer706*707* @return the number of bytes stored in <code>output</code>708*709* @exception IllegalBlockSizeException if this cipher is a block cipher,710* no padding has been requested (only in encryption mode), and the total711* input length of the data processed by this cipher is not a multiple of712* block size; or if this encryption algorithm is unable to713* process the input data provided.714* @exception ShortBufferException if there is insufficient space in the715* output buffer716* @exception BadPaddingException if this cipher is in decryption mode,717* and (un)padding has been requested, but the decrypted data is not718* bounded by the appropriate padding bytes719* @exception AEADBadTagException if this cipher is decrypting in an720* AEAD mode (such as GCM/CCM), and the received authentication tag721* does not match the calculated value722*723* @throws NullPointerException if either parameter is <CODE>null</CODE>724* @since 1.5725*/726protected int engineDoFinal(ByteBuffer input, ByteBuffer output)727throws ShortBufferException, IllegalBlockSizeException,728BadPaddingException {729return bufferCrypt(input, output, false);730}731732// copied from sun.security.jca.JCAUtil733// will be changed to reference that method once that code has been734// integrated and promoted735static int getTempArraySize(int totalSize) {736return Math.min(4096, totalSize);737}738739/**740* Implementation for encryption using ByteBuffers. Used for both741* engineUpdate() and engineDoFinal().742*/743private int bufferCrypt(ByteBuffer input, ByteBuffer output,744boolean isUpdate) throws ShortBufferException,745IllegalBlockSizeException, BadPaddingException {746if ((input == null) || (output == null)) {747throw new NullPointerException748("Input and output buffers must not be null");749}750int inPos = input.position();751int inLimit = input.limit();752int inLen = inLimit - inPos;753if (isUpdate && (inLen == 0)) {754return 0;755}756int outLenNeeded = engineGetOutputSize(inLen);757758if (output.remaining() < outLenNeeded) {759throw new ShortBufferException("Need at least " + outLenNeeded760+ " bytes of space in output buffer");761}762763boolean a1 = input.hasArray();764boolean a2 = output.hasArray();765int total = 0;766byte[] inArray, outArray;767if (a2) { // output has an accessible byte[]768outArray = output.array();769int outPos = output.position();770int outOfs = output.arrayOffset() + outPos;771772if (a1) { // input also has an accessible byte[]773inArray = input.array();774int inOfs = input.arrayOffset() + inPos;775if (isUpdate) {776total = engineUpdate(inArray, inOfs, inLen, outArray, outOfs);777} else {778total = engineDoFinal(inArray, inOfs, inLen, outArray, outOfs);779}780input.position(inLimit);781} else { // input does not have accessible byte[]782inArray = new byte[getTempArraySize(inLen)];783do {784int chunk = Math.min(inLen, inArray.length);785if (chunk > 0) {786input.get(inArray, 0, chunk);787}788int n;789if (isUpdate || (inLen > chunk)) {790n = engineUpdate(inArray, 0, chunk, outArray, outOfs);791} else {792n = engineDoFinal(inArray, 0, chunk, outArray, outOfs);793}794total += n;795outOfs += n;796inLen -= chunk;797} while (inLen > 0);798}799output.position(outPos + total);800} else { // output does not have an accessible byte[]801if (a1) { // but input has an accessible byte[]802inArray = input.array();803int inOfs = input.arrayOffset() + inPos;804if (isUpdate) {805outArray = engineUpdate(inArray, inOfs, inLen);806} else {807outArray = engineDoFinal(inArray, inOfs, inLen);808}809input.position(inLimit);810if (outArray != null && outArray.length != 0) {811output.put(outArray);812total = outArray.length;813}814} else { // input also does not have an accessible byte[]815inArray = new byte[getTempArraySize(inLen)];816do {817int chunk = Math.min(inLen, inArray.length);818if (chunk > 0) {819input.get(inArray, 0, chunk);820}821int n;822if (isUpdate || (inLen > chunk)) {823outArray = engineUpdate(inArray, 0, chunk);824} else {825outArray = engineDoFinal(inArray, 0, chunk);826}827if (outArray != null && outArray.length != 0) {828output.put(outArray);829total += outArray.length;830}831inLen -= chunk;832} while (inLen > 0);833}834}835return total;836}837838/**839* Wrap a key.840*841* <p>This concrete method has been added to this previously-defined842* abstract class. (For backwards compatibility, it cannot be abstract.)843* It may be overridden by a provider to wrap a key.844* Such an override is expected to throw an IllegalBlockSizeException or845* InvalidKeyException (under the specified circumstances),846* if the given key cannot be wrapped.847* If this method is not overridden, it always throws an848* UnsupportedOperationException.849*850* @param key the key to be wrapped.851*852* @return the wrapped key.853*854* @exception IllegalBlockSizeException if this cipher is a block cipher,855* no padding has been requested, and the length of the encoding of the856* key to be wrapped is not a multiple of the block size.857*858* @exception InvalidKeyException if it is impossible or unsafe to859* wrap the key with this cipher (e.g., a hardware protected key is860* being passed to a software-only cipher).861*862* @throws UnsupportedOperationException if this method is not supported.863*/864protected byte[] engineWrap(Key key)865throws IllegalBlockSizeException, InvalidKeyException866{867throw new UnsupportedOperationException();868}869870/**871* Unwrap a previously wrapped key.872*873* <p>This concrete method has been added to this previously-defined874* abstract class. (For backwards compatibility, it cannot be abstract.)875* It may be overridden by a provider to unwrap a previously wrapped key.876* Such an override is expected to throw an InvalidKeyException if877* the given wrapped key cannot be unwrapped.878* If this method is not overridden, it always throws an879* UnsupportedOperationException.880*881* @param wrappedKey the key to be unwrapped.882*883* @param wrappedKeyAlgorithm the algorithm associated with the wrapped884* key.885*886* @param wrappedKeyType the type of the wrapped key. This is one of887* <code>SECRET_KEY</code>, <code>PRIVATE_KEY</code>, or888* <code>PUBLIC_KEY</code>.889*890* @return the unwrapped key.891*892* @exception NoSuchAlgorithmException if no installed providers893* can create keys of type <code>wrappedKeyType</code> for the894* <code>wrappedKeyAlgorithm</code>.895*896* @exception InvalidKeyException if <code>wrappedKey</code> does not897* represent a wrapped key of type <code>wrappedKeyType</code> for898* the <code>wrappedKeyAlgorithm</code>.899*900* @throws UnsupportedOperationException if this method is not supported.901*/902protected Key engineUnwrap(byte[] wrappedKey,903String wrappedKeyAlgorithm,904int wrappedKeyType)905throws InvalidKeyException, NoSuchAlgorithmException906{907throw new UnsupportedOperationException();908}909910/**911* Returns the key size of the given key object in bits.912* <p>This concrete method has been added to this previously-defined913* abstract class. It throws an <code>UnsupportedOperationException</code>914* if it is not overridden by the provider.915*916* @param key the key object.917*918* @return the key size of the given key object.919*920* @exception InvalidKeyException if <code>key</code> is invalid.921*/922protected int engineGetKeySize(Key key)923throws InvalidKeyException924{925throw new UnsupportedOperationException();926}927928/**929* Continues a multi-part update of the Additional Authentication930* Data (AAD), using a subset of the provided buffer.931* <p>932* Calls to this method provide AAD to the cipher when operating in933* modes such as AEAD (GCM/CCM). If this cipher is operating in934* either GCM or CCM mode, all AAD must be supplied before beginning935* operations on the ciphertext (via the {@code update} and {@code936* doFinal} methods).937*938* @param src the buffer containing the AAD939* @param offset the offset in {@code src} where the AAD input starts940* @param len the number of AAD bytes941*942* @throws IllegalStateException if this cipher is in a wrong state943* (e.g., has not been initialized), does not accept AAD, or if944* operating in either GCM or CCM mode and one of the {@code update}945* methods has already been called for the active946* encryption/decryption operation947* @throws UnsupportedOperationException if this method948* has not been overridden by an implementation949*950* @since 1.7951*/952protected void engineUpdateAAD(byte[] src, int offset, int len) {953throw new UnsupportedOperationException(954"The underlying Cipher implementation "955+ "does not support this method");956}957958/**959* Continues a multi-part update of the Additional Authentication960* Data (AAD).961* <p>962* Calls to this method provide AAD to the cipher when operating in963* modes such as AEAD (GCM/CCM). If this cipher is operating in964* either GCM or CCM mode, all AAD must be supplied before beginning965* operations on the ciphertext (via the {@code update} and {@code966* doFinal} methods).967* <p>968* All {@code src.remaining()} bytes starting at969* {@code src.position()} are processed.970* Upon return, the input buffer's position will be equal971* to its limit; its limit will not have changed.972*973* @param src the buffer containing the AAD974*975* @throws IllegalStateException if this cipher is in a wrong state976* (e.g., has not been initialized), does not accept AAD, or if977* operating in either GCM or CCM mode and one of the {@code update}978* methods has already been called for the active979* encryption/decryption operation980* @throws UnsupportedOperationException if this method981* has not been overridden by an implementation982*983* @since 1.7984*/985protected void engineUpdateAAD(ByteBuffer src) {986throw new UnsupportedOperationException(987"The underlying Cipher implementation "988+ "does not support this method");989}990}991992993