Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/com/sun/crypto/provider/AESCipher.java
38922 views
/*1* Copyright (c) 2002, 2017, 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 com.sun.crypto.provider;2627import java.security.*;28import java.security.spec.*;29import javax.crypto.*;30import javax.crypto.spec.*;31import javax.crypto.BadPaddingException;32import java.nio.ByteBuffer;3334/**35* This class implements the AES algorithm in its various modes36* (<code>ECB</code>, <code>CFB</code>, <code>OFB</code>, <code>CBC</code>,37* <code>PCBC</code>) and padding schemes (<code>PKCS5Padding</code>,38* <code>NoPadding</code>, <code>ISO10126Padding</code>).39*40* @author Valerie Peng41*42*43* @see AESCrypt44* @see CipherBlockChaining45* @see ElectronicCodeBook46* @see CipherFeedback47* @see OutputFeedback48*/4950abstract class AESCipher extends CipherSpi {51public static final class General extends AESCipher {52public General() {53super(-1);54}55}56abstract static class OidImpl extends AESCipher {57protected OidImpl(int keySize, String mode, String padding) {58super(keySize);59try {60engineSetMode(mode);61engineSetPadding(padding);62} catch (GeneralSecurityException gse) {63// internal error; re-throw as provider exception64ProviderException pe =new ProviderException("Internal Error");65pe.initCause(gse);66throw pe;67}68}69}70public static final class AES128_ECB_NoPadding extends OidImpl {71public AES128_ECB_NoPadding() {72super(16, "ECB", "NOPADDING");73}74}75public static final class AES192_ECB_NoPadding extends OidImpl {76public AES192_ECB_NoPadding() {77super(24, "ECB", "NOPADDING");78}79}80public static final class AES256_ECB_NoPadding extends OidImpl {81public AES256_ECB_NoPadding() {82super(32, "ECB", "NOPADDING");83}84}85public static final class AES128_CBC_NoPadding extends OidImpl {86public AES128_CBC_NoPadding() {87super(16, "CBC", "NOPADDING");88}89}90public static final class AES192_CBC_NoPadding extends OidImpl {91public AES192_CBC_NoPadding() {92super(24, "CBC", "NOPADDING");93}94}95public static final class AES256_CBC_NoPadding extends OidImpl {96public AES256_CBC_NoPadding() {97super(32, "CBC", "NOPADDING");98}99}100public static final class AES128_OFB_NoPadding extends OidImpl {101public AES128_OFB_NoPadding() {102super(16, "OFB", "NOPADDING");103}104}105public static final class AES192_OFB_NoPadding extends OidImpl {106public AES192_OFB_NoPadding() {107super(24, "OFB", "NOPADDING");108}109}110public static final class AES256_OFB_NoPadding extends OidImpl {111public AES256_OFB_NoPadding() {112super(32, "OFB", "NOPADDING");113}114}115public static final class AES128_CFB_NoPadding extends OidImpl {116public AES128_CFB_NoPadding() {117super(16, "CFB", "NOPADDING");118}119}120public static final class AES192_CFB_NoPadding extends OidImpl {121public AES192_CFB_NoPadding() {122super(24, "CFB", "NOPADDING");123}124}125public static final class AES256_CFB_NoPadding extends OidImpl {126public AES256_CFB_NoPadding() {127super(32, "CFB", "NOPADDING");128}129}130public static final class AES128_GCM_NoPadding extends OidImpl {131public AES128_GCM_NoPadding() {132super(16, "GCM", "NOPADDING");133}134}135public static final class AES192_GCM_NoPadding extends OidImpl {136public AES192_GCM_NoPadding() {137super(24, "GCM", "NOPADDING");138}139}140public static final class AES256_GCM_NoPadding extends OidImpl {141public AES256_GCM_NoPadding() {142super(32, "GCM", "NOPADDING");143}144}145146// utility method used by AESCipher and AESWrapCipher147static final void checkKeySize(Key key, int fixedKeySize)148throws InvalidKeyException {149if (fixedKeySize != -1) {150if (key == null) {151throw new InvalidKeyException("The key must not be null");152}153byte[] value = key.getEncoded();154if (value == null) {155throw new InvalidKeyException("Key encoding must not be null");156} else if (value.length != fixedKeySize) {157throw new InvalidKeyException("The key must be " +158fixedKeySize + " bytes");159}160}161}162163/*164* internal CipherCore object which does the real work.165*/166private CipherCore core = null;167168/*169* needed to support AES oids which associates a fixed key size170* to the cipher object.171*/172private final int fixedKeySize; // in bytes, -1 if no restriction173174/*175* needed to enforce ISE thrown when updateAAD is called after update for GCM mode.176*/177private boolean updateCalled;178179/**180* Creates an instance of AES cipher with default ECB mode and181* PKCS5Padding.182*/183protected AESCipher(int keySize) {184core = new CipherCore(new AESCrypt(), AESConstants.AES_BLOCK_SIZE);185fixedKeySize = keySize;186}187188/**189* Sets the mode of this cipher.190*191* @param mode the cipher mode192*193* @exception NoSuchAlgorithmException if the requested cipher mode does194* not exist195*/196protected void engineSetMode(String mode)197throws NoSuchAlgorithmException {198core.setMode(mode);199}200201/**202* Sets the padding mechanism of this cipher.203*204* @param padding the padding mechanism205*206* @exception NoSuchPaddingException if the requested padding mechanism207* does not exist208*/209protected void engineSetPadding(String paddingScheme)210throws NoSuchPaddingException {211core.setPadding(paddingScheme);212}213214/**215* Returns the block size (in bytes).216*217* @return the block size (in bytes), or 0 if the underlying algorithm is218* not a block cipher219*/220protected int engineGetBlockSize() {221return AESConstants.AES_BLOCK_SIZE;222}223224/**225* Returns the length in bytes that an output buffer would need to be in226* order to hold the result of the next <code>update</code> or227* <code>doFinal</code> operation, given the input length228* <code>inputLen</code> (in bytes).229*230* <p>This call takes into account any unprocessed (buffered) data from a231* previous <code>update</code> call, and padding.232*233* <p>The actual output length of the next <code>update</code> or234* <code>doFinal</code> call may be smaller than the length returned by235* this method.236*237* @param inputLen the input length (in bytes)238*239* @return the required output buffer size (in bytes)240*/241protected int engineGetOutputSize(int inputLen) {242return core.getOutputSize(inputLen);243}244245/**246* Returns the initialization vector (IV) in a new buffer.247*248* <p>This is useful in the case where a random IV has been created249* (see <a href = "#init">init</a>),250* or in the context of password-based encryption or251* decryption, where the IV is derived from a user-provided password.252*253* @return the initialization vector in a new buffer, or null if the254* underlying algorithm does not use an IV, or if the IV has not yet255* been set.256*/257protected byte[] engineGetIV() {258return core.getIV();259}260261/**262* Returns the parameters used with this cipher.263*264* <p>The returned parameters may be the same that were used to initialize265* this cipher, or may contain the default set of parameters or a set of266* randomly generated parameters used by the underlying cipher267* implementation (provided that the underlying cipher implementation268* uses a default set of parameters or creates new parameters if it needs269* parameters but was not initialized with any).270*271* @return the parameters used with this cipher, or null if this cipher272* does not use any parameters.273*/274protected AlgorithmParameters engineGetParameters() {275return core.getParameters("AES");276}277278/**279* Initializes this cipher with a key and a source of randomness.280*281* <p>The cipher is initialized for one of the following four operations:282* encryption, decryption, key wrapping or key unwrapping, depending on283* the value of <code>opmode</code>.284*285* <p>If this cipher requires an initialization vector (IV), it will get286* it from <code>random</code>.287* This behaviour should only be used in encryption or key wrapping288* mode, however.289* When initializing a cipher that requires an IV for decryption or290* key unwrapping, the IV291* (same IV that was used for encryption or key wrapping) must be provided292* explicitly as a293* parameter, in order to get the correct result.294*295* <p>This method also cleans existing buffer and other related state296* information.297*298* @param opmode the operation mode of this cipher (this is one of299* the following:300* <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,301* <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)302* @param key the secret key303* @param random the source of randomness304*305* @exception InvalidKeyException if the given key is inappropriate for306* initializing this cipher307*/308protected void engineInit(int opmode, Key key, SecureRandom random)309throws InvalidKeyException {310checkKeySize(key, fixedKeySize);311updateCalled = false;312core.init(opmode, key, random);313}314315/**316* Initializes this cipher with a key, a set of317* algorithm parameters, and a source of randomness.318*319* <p>The cipher is initialized for one of the following four operations:320* encryption, decryption, key wrapping or key unwrapping, depending on321* the value of <code>opmode</code>.322*323* <p>If this cipher (including its underlying feedback or padding scheme)324* requires any random bytes, it will get them from <code>random</code>.325*326* @param opmode the operation mode of this cipher (this is one of327* the following:328* <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,329* <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)330* @param key the encryption key331* @param params the algorithm parameters332* @param random the source of randomness333*334* @exception InvalidKeyException if the given key is inappropriate for335* initializing this cipher336* @exception InvalidAlgorithmParameterException if the given algorithm337* parameters are inappropriate for this cipher338*/339protected void engineInit(int opmode, Key key,340AlgorithmParameterSpec params,341SecureRandom random)342throws InvalidKeyException, InvalidAlgorithmParameterException {343checkKeySize(key, fixedKeySize);344updateCalled = false;345core.init(opmode, key, params, random);346}347348protected void engineInit(int opmode, Key key,349AlgorithmParameters params,350SecureRandom random)351throws InvalidKeyException, InvalidAlgorithmParameterException {352checkKeySize(key, fixedKeySize);353updateCalled = false;354core.init(opmode, key, params, random);355}356357/**358* Continues a multiple-part encryption or decryption operation359* (depending on how this cipher was initialized), processing another data360* part.361*362* <p>The first <code>inputLen</code> bytes in the <code>input</code>363* buffer, starting at <code>inputOffset</code>, are processed, and the364* result is stored in a new buffer.365*366* @param input the input buffer367* @param inputOffset the offset in <code>input</code> where the input368* starts369* @param inputLen the input length370*371* @return the new buffer with the result372*373* @exception IllegalStateException if this cipher is in a wrong state374* (e.g., has not been initialized)375*/376protected byte[] engineUpdate(byte[] input, int inputOffset,377int inputLen) {378updateCalled = true;379return core.update(input, inputOffset, inputLen);380}381382/**383* Continues a multiple-part encryption or decryption operation384* (depending on how this cipher was initialized), processing another data385* part.386*387* <p>The first <code>inputLen</code> bytes in the <code>input</code>388* buffer, starting at <code>inputOffset</code>, are processed, and the389* result is stored in the <code>output</code> buffer, starting at390* <code>outputOffset</code>.391*392* @param input the input buffer393* @param inputOffset the offset in <code>input</code> where the input394* starts395* @param inputLen the input length396* @param output the buffer for the result397* @param outputOffset the offset in <code>output</code> where the result398* is stored399*400* @return the number of bytes stored in <code>output</code>401*402* @exception ShortBufferException if the given output buffer is too small403* to hold the result404*/405protected int engineUpdate(byte[] input, int inputOffset, int inputLen,406byte[] output, int outputOffset)407throws ShortBufferException {408updateCalled = true;409return core.update(input, inputOffset, inputLen, output,410outputOffset);411}412413/**414* Encrypts or decrypts data in a single-part operation,415* or finishes a multiple-part operation.416* The data is encrypted or decrypted, depending on how this cipher was417* initialized.418*419* <p>The first <code>inputLen</code> bytes in the <code>input</code>420* buffer, starting at <code>inputOffset</code>, and any input bytes that421* may have been buffered during a previous <code>update</code> operation,422* are processed, with padding (if requested) being applied.423* The result is stored in a new buffer.424*425* <p>The cipher is reset to its initial state (uninitialized) after this426* call.427*428* @param input the input buffer429* @param inputOffset the offset in <code>input</code> where the input430* starts431* @param inputLen the input length432*433* @return the new buffer with the result434*435* @exception IllegalBlockSizeException if this cipher is a block cipher,436* no padding has been requested (only in encryption mode), and the total437* input length of the data processed by this cipher is not a multiple of438* block size439* @exception BadPaddingException if this cipher is in decryption mode,440* and (un)padding has been requested, but the decrypted data is not441* bounded by the appropriate padding bytes442*/443protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)444throws IllegalBlockSizeException, BadPaddingException {445byte[] out = core.doFinal(input, inputOffset, inputLen);446updateCalled = false;447return out;448}449450/**451* Encrypts or decrypts data in a single-part operation,452* or finishes a multiple-part operation.453* The data is encrypted or decrypted, depending on how this cipher was454* initialized.455*456* <p>The first <code>inputLen</code> bytes in the <code>input</code>457* buffer, starting at <code>inputOffset</code>, and any input bytes that458* may have been buffered during a previous <code>update</code> operation,459* are processed, with padding (if requested) being applied.460* The result is stored in the <code>output</code> buffer, starting at461* <code>outputOffset</code>.462*463* <p>The cipher is reset to its initial state (uninitialized) after this464* call.465*466* @param input the input buffer467* @param inputOffset the offset in <code>input</code> where the input468* starts469* @param inputLen the input length470* @param output the buffer for the result471* @param outputOffset the offset in <code>output</code> where the result472* is stored473*474* @return the number of bytes stored in <code>output</code>475*476* @exception IllegalBlockSizeException if this cipher is a block cipher,477* no padding has been requested (only in encryption mode), and the total478* input length of the data processed by this cipher is not a multiple of479* block size480* @exception ShortBufferException if the given output buffer is too small481* to hold the result482* @exception BadPaddingException if this cipher is in decryption mode,483* and (un)padding has been requested, but the decrypted data is not484* bounded by the appropriate padding bytes485*/486protected int engineDoFinal(byte[] input, int inputOffset, int inputLen,487byte[] output, int outputOffset)488throws IllegalBlockSizeException, ShortBufferException,489BadPaddingException {490int outLen = core.doFinal(input, inputOffset, inputLen, output,491outputOffset);492updateCalled = false;493return outLen;494}495496/**497* Returns the key size of the given key object.498*499* @param key the key object.500*501* @return the key size of the given key object.502*503* @exception InvalidKeyException if <code>key</code> is invalid.504*/505protected int engineGetKeySize(Key key) throws InvalidKeyException {506byte[] encoded = key.getEncoded();507if (!AESCrypt.isKeySizeValid(encoded.length)) {508throw new InvalidKeyException("Invalid AES key length: " +509encoded.length + " bytes");510}511return Math.multiplyExact(encoded.length, 8);512}513514/**515* Wrap a key.516*517* @param key the key to be wrapped.518*519* @return the wrapped key.520*521* @exception IllegalBlockSizeException if this cipher is a block522* cipher, no padding has been requested, and the length of the523* encoding of the key to be wrapped is not a524* multiple of the block size.525*526* @exception InvalidKeyException if it is impossible or unsafe to527* wrap the key with this cipher (e.g., a hardware protected key is528* being passed to a software only cipher).529*/530protected byte[] engineWrap(Key key)531throws IllegalBlockSizeException, InvalidKeyException {532return core.wrap(key);533}534535/**536* Unwrap a previously wrapped key.537*538* @param wrappedKey the key to be unwrapped.539*540* @param wrappedKeyAlgorithm the algorithm the wrapped key is for.541*542* @param wrappedKeyType the type of the wrapped key.543* This is one of <code>Cipher.SECRET_KEY</code>,544* <code>Cipher.PRIVATE_KEY</code>, or <code>Cipher.PUBLIC_KEY</code>.545*546* @return the unwrapped key.547*548* @exception NoSuchAlgorithmException if no installed providers549* can create keys of type <code>wrappedKeyType</code> for the550* <code>wrappedKeyAlgorithm</code>.551*552* @exception InvalidKeyException if <code>wrappedKey</code> does not553* represent a wrapped key of type <code>wrappedKeyType</code> for554* the <code>wrappedKeyAlgorithm</code>.555*/556protected Key engineUnwrap(byte[] wrappedKey,557String wrappedKeyAlgorithm,558int wrappedKeyType)559throws InvalidKeyException, NoSuchAlgorithmException {560return core.unwrap(wrappedKey, wrappedKeyAlgorithm,561wrappedKeyType);562}563564/**565* Continues a multi-part update of the Additional Authentication566* Data (AAD), using a subset of the provided buffer.567* <p>568* Calls to this method provide AAD to the cipher when operating in569* modes such as AEAD (GCM/CCM). If this cipher is operating in570* either GCM or CCM mode, all AAD must be supplied before beginning571* operations on the ciphertext (via the {@code update} and {@code572* doFinal} methods).573*574* @param src the buffer containing the AAD575* @param offset the offset in {@code src} where the AAD input starts576* @param len the number of AAD bytes577*578* @throws IllegalStateException if this cipher is in a wrong state579* (e.g., has not been initialized), does not accept AAD, or if580* operating in either GCM or CCM mode and one of the {@code update}581* methods has already been called for the active582* encryption/decryption operation583* @throws UnsupportedOperationException if this method584* has not been overridden by an implementation585*586* @since 1.8587*/588@Override589protected void engineUpdateAAD(byte[] src, int offset, int len) {590if (core.getMode() == CipherCore.GCM_MODE && updateCalled) {591throw new IllegalStateException("AAD must be supplied before encryption/decryption starts");592}593core.updateAAD(src, offset, len);594}595596/**597* Continues a multi-part update of the Additional Authentication598* Data (AAD).599* <p>600* Calls to this method provide AAD to the cipher when operating in601* modes such as AEAD (GCM/CCM). If this cipher is operating in602* either GCM or CCM mode, all AAD must be supplied before beginning603* operations on the ciphertext (via the {@code update} and {@code604* doFinal} methods).605* <p>606* All {@code src.remaining()} bytes starting at607* {@code src.position()} are processed.608* Upon return, the input buffer's position will be equal609* to its limit; its limit will not have changed.610*611* @param src the buffer containing the AAD612*613* @throws IllegalStateException if this cipher is in a wrong state614* (e.g., has not been initialized), does not accept AAD, or if615* operating in either GCM or CCM mode and one of the {@code update}616* methods has already been called for the active617* encryption/decryption operation618* @throws UnsupportedOperationException if this method619* has not been overridden by an implementation620*621* @since 1.8622*/623@Override624protected void engineUpdateAAD(ByteBuffer src) {625if (core.getMode() == CipherCore.GCM_MODE && updateCalled) {626throw new IllegalStateException("AAD must be supplied before encryption/decryption starts");627}628if (src != null) {629int aadLen = src.limit() - src.position();630if (aadLen > 0) {631if (src.hasArray()) {632int aadOfs = Math.addExact(src.arrayOffset(), src.position());633core.updateAAD(src.array(), aadOfs, aadLen);634src.position(src.limit());635} else {636byte[] aad = new byte[aadLen];637src.get(aad);638core.updateAAD(aad, 0, aadLen);639}640}641}642}643}644645646647