Path: blob/master/src/java.base/share/classes/com/sun/crypto/provider/AESCipher.java
67854 views
/*1* Copyright (c) 2002, 2021, 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 javax.crypto.BadPaddingException;28import javax.crypto.CipherSpi;29import javax.crypto.IllegalBlockSizeException;30import javax.crypto.NoSuchPaddingException;31import javax.crypto.ShortBufferException;32import java.nio.ByteBuffer;33import java.security.AlgorithmParameters;34import java.security.GeneralSecurityException;35import java.security.InvalidAlgorithmParameterException;36import java.security.InvalidKeyException;37import java.security.Key;38import java.security.NoSuchAlgorithmException;39import java.security.ProviderException;40import java.security.SecureRandom;41import java.security.spec.AlgorithmParameterSpec;42import java.util.Arrays;4344/**45* This class implements the AES algorithm in its various modes46* (<code>ECB</code>, <code>CFB</code>, <code>OFB</code>, <code>CBC</code>,47* <code>PCBC</code>) and padding schemes (<code>PKCS5Padding</code>,48* <code>NoPadding</code>, <code>ISO10126Padding</code>).49*50* @author Valerie Peng51*52*53* @see AESCrypt54* @see CipherBlockChaining55* @see ElectronicCodeBook56* @see CipherFeedback57* @see OutputFeedback58*/5960abstract class AESCipher extends CipherSpi {61public static final class General extends AESCipher {62public General() {63super(-1);64}65}66abstract static class OidImpl extends AESCipher {67protected OidImpl(int keySize, String mode, String padding) {68super(keySize);69try {70engineSetMode(mode);71engineSetPadding(padding);72} catch (GeneralSecurityException gse) {73// internal error; re-throw as provider exception74ProviderException pe =new ProviderException("Internal Error");75pe.initCause(gse);76throw pe;77}78}79}80public static final class AES128_ECB_NoPadding extends OidImpl {81public AES128_ECB_NoPadding() {82super(16, "ECB", "NOPADDING");83}84}85public static final class AES192_ECB_NoPadding extends OidImpl {86public AES192_ECB_NoPadding() {87super(24, "ECB", "NOPADDING");88}89}90public static final class AES256_ECB_NoPadding extends OidImpl {91public AES256_ECB_NoPadding() {92super(32, "ECB", "NOPADDING");93}94}95public static final class AES128_CBC_NoPadding extends OidImpl {96public AES128_CBC_NoPadding() {97super(16, "CBC", "NOPADDING");98}99}100public static final class AES192_CBC_NoPadding extends OidImpl {101public AES192_CBC_NoPadding() {102super(24, "CBC", "NOPADDING");103}104}105public static final class AES256_CBC_NoPadding extends OidImpl {106public AES256_CBC_NoPadding() {107super(32, "CBC", "NOPADDING");108}109}110public static final class AES128_OFB_NoPadding extends OidImpl {111public AES128_OFB_NoPadding() {112super(16, "OFB", "NOPADDING");113}114}115public static final class AES192_OFB_NoPadding extends OidImpl {116public AES192_OFB_NoPadding() {117super(24, "OFB", "NOPADDING");118}119}120public static final class AES256_OFB_NoPadding extends OidImpl {121public AES256_OFB_NoPadding() {122super(32, "OFB", "NOPADDING");123}124}125public static final class AES128_CFB_NoPadding extends OidImpl {126public AES128_CFB_NoPadding() {127super(16, "CFB", "NOPADDING");128}129}130public static final class AES192_CFB_NoPadding extends OidImpl {131public AES192_CFB_NoPadding() {132super(24, "CFB", "NOPADDING");133}134}135public static final class AES256_CFB_NoPadding extends OidImpl {136public AES256_CFB_NoPadding() {137super(32, "CFB", "NOPADDING");138}139}140141// utility method used by AESCipher and AESWrapCipher142static final void checkKeySize(Key key, int fixedKeySize)143throws InvalidKeyException {144if (fixedKeySize != -1) {145if (key == null) {146throw new InvalidKeyException("The key must not be null");147}148byte[] value = key.getEncoded();149if (value == null) {150throw new InvalidKeyException("Key encoding must not be null");151} else {152Arrays.fill(value, (byte)0);153if (value.length != fixedKeySize) {154throw new InvalidKeyException("The key must be " +155fixedKeySize + " bytes");156}157}158}159}160161/*162* internal CipherCore object which does the real work.163*/164private CipherCore core = null;165166/*167* needed to support AES oids which associates a fixed key size168* to the cipher object.169*/170private final int fixedKeySize; // in bytes, -1 if no restriction171172173/**174* Creates an instance of AES cipher with default ECB mode and175* PKCS5Padding.176*/177protected AESCipher(int keySize) {178core = new CipherCore(new AESCrypt(), AESConstants.AES_BLOCK_SIZE);179fixedKeySize = keySize;180}181182/**183* Sets the mode of this cipher.184*185* @param mode the cipher mode186*187* @exception NoSuchAlgorithmException if the requested cipher mode does188* not exist189*/190protected void engineSetMode(String mode)191throws NoSuchAlgorithmException {192core.setMode(mode);193}194195/**196* Sets the padding mechanism of this cipher.197*198* @param paddingScheme the padding mechanism199*200* @exception NoSuchPaddingException if the requested padding mechanism201* does not exist202*/203protected void engineSetPadding(String paddingScheme)204throws NoSuchPaddingException {205core.setPadding(paddingScheme);206}207208/**209* Returns the block size (in bytes).210*211* @return the block size (in bytes), or 0 if the underlying algorithm is212* not a block cipher213*/214protected int engineGetBlockSize() {215return AESConstants.AES_BLOCK_SIZE;216}217218/**219* Returns the length in bytes that an output buffer would need to be in220* order to hold the result of the next <code>update</code> or221* <code>doFinal</code> operation, given the input length222* <code>inputLen</code> (in bytes).223*224* <p>This call takes into account any unprocessed (buffered) data from a225* previous <code>update</code> call, and padding.226*227* <p>The actual output length of the next <code>update</code> or228* <code>doFinal</code> call may be smaller than the length returned by229* this method.230*231* @param inputLen the input length (in bytes)232*233* @return the required output buffer size (in bytes)234*/235protected int engineGetOutputSize(int inputLen) {236return core.getOutputSize(inputLen);237}238239/**240* Returns the initialization vector (IV) in a new buffer.241*242* <p>This is useful in the case where a random IV has been created243* (see <a href = "#init">init</a>),244* or in the context of password-based encryption or245* decryption, where the IV is derived from a user-provided password.246*247* @return the initialization vector in a new buffer, or null if the248* underlying algorithm does not use an IV, or if the IV has not yet249* been set.250*/251protected byte[] engineGetIV() {252return core.getIV();253}254255/**256* Returns the parameters used with this cipher.257*258* <p>The returned parameters may be the same that were used to initialize259* this cipher, or may contain the default set of parameters or a set of260* randomly generated parameters used by the underlying cipher261* implementation (provided that the underlying cipher implementation262* uses a default set of parameters or creates new parameters if it needs263* parameters but was not initialized with any).264*265* @return the parameters used with this cipher, or null if this cipher266* does not use any parameters.267*/268protected AlgorithmParameters engineGetParameters() {269return core.getParameters("AES");270}271272/**273* Initializes this cipher with a key and a source of randomness.274*275* <p>The cipher is initialized for one of the following four operations:276* encryption, decryption, key wrapping or key unwrapping, depending on277* the value of <code>opmode</code>.278*279* <p>If this cipher requires an initialization vector (IV), it will get280* it from <code>random</code>.281* This behaviour should only be used in encryption or key wrapping282* mode, however.283* When initializing a cipher that requires an IV for decryption or284* key unwrapping, the IV285* (same IV that was used for encryption or key wrapping) must be provided286* explicitly as a287* parameter, in order to get the correct result.288*289* <p>This method also cleans existing buffer and other related state290* information.291*292* @param opmode the operation mode of this cipher (this is one of293* the following:294* <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,295* <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)296* @param key the secret key297* @param random the source of randomness298*299* @exception InvalidKeyException if the given key is inappropriate for300* initializing this cipher301*/302protected void engineInit(int opmode, Key key, SecureRandom random)303throws InvalidKeyException {304checkKeySize(key, fixedKeySize);305core.init(opmode, key, random);306}307308/**309* Initializes this cipher with a key, a set of310* algorithm parameters, and a source of randomness.311*312* <p>The cipher is initialized for one of the following four operations:313* encryption, decryption, key wrapping or key unwrapping, depending on314* the value of <code>opmode</code>.315*316* <p>If this cipher (including its underlying feedback or padding scheme)317* requires any random bytes, it will get them from <code>random</code>.318*319* @param opmode the operation mode of this cipher (this is one of320* the following:321* <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,322* <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)323* @param key the encryption key324* @param params the algorithm parameters325* @param random the source of randomness326*327* @exception InvalidKeyException if the given key is inappropriate for328* initializing this cipher329* @exception InvalidAlgorithmParameterException if the given algorithm330* parameters are inappropriate for this cipher331*/332protected void engineInit(int opmode, Key key,333AlgorithmParameterSpec params,334SecureRandom random)335throws InvalidKeyException, InvalidAlgorithmParameterException {336checkKeySize(key, fixedKeySize);337core.init(opmode, key, params, random);338}339340protected void engineInit(int opmode, Key key,341AlgorithmParameters params,342SecureRandom random)343throws InvalidKeyException, InvalidAlgorithmParameterException {344checkKeySize(key, fixedKeySize);345core.init(opmode, key, params, random);346}347348/**349* Continues a multiple-part encryption or decryption operation350* (depending on how this cipher was initialized), processing another data351* part.352*353* <p>The first <code>inputLen</code> bytes in the <code>input</code>354* buffer, starting at <code>inputOffset</code>, are processed, and the355* result is stored in a new buffer.356*357* @param input the input buffer358* @param inputOffset the offset in <code>input</code> where the input359* starts360* @param inputLen the input length361*362* @return the new buffer with the result363*364* @exception IllegalStateException if this cipher is in a wrong state365* (e.g., has not been initialized)366*/367protected byte[] engineUpdate(byte[] input, int inputOffset,368int inputLen) {369return core.update(input, inputOffset, inputLen);370}371372/**373* Continues a multiple-part encryption or decryption operation374* (depending on how this cipher was initialized), processing another data375* part.376*377* <p>The first <code>inputLen</code> bytes in the <code>input</code>378* buffer, starting at <code>inputOffset</code>, are processed, and the379* result is stored in the <code>output</code> buffer, starting at380* <code>outputOffset</code>.381*382* @param input the input buffer383* @param inputOffset the offset in <code>input</code> where the input384* starts385* @param inputLen the input length386* @param output the buffer for the result387* @param outputOffset the offset in <code>output</code> where the result388* is stored389*390* @return the number of bytes stored in <code>output</code>391*392* @exception ShortBufferException if the given output buffer is too small393* to hold the result394*/395protected int engineUpdate(byte[] input, int inputOffset, int inputLen,396byte[] output, int outputOffset)397throws ShortBufferException {398return core.update(input, inputOffset, inputLen, output,399outputOffset);400}401402403/**404* Encrypts or decrypts data in a single-part operation,405* or finishes a multiple-part operation.406* The data is encrypted or decrypted, depending on how this cipher was407* initialized.408*409* <p>The first <code>inputLen</code> bytes in the <code>input</code>410* buffer, starting at <code>inputOffset</code>, and any input bytes that411* may have been buffered during a previous <code>update</code> operation,412* are processed, with padding (if requested) being applied.413* The result is stored in a new buffer.414*415* <p>The cipher is reset to its initial state (uninitialized) after this416* call.417*418* @param input the input buffer419* @param inputOffset the offset in <code>input</code> where the input420* starts421* @param inputLen the input length422*423* @return the new buffer with the result424*425* @exception IllegalBlockSizeException if this cipher is a block cipher,426* no padding has been requested (only in encryption mode), and the total427* input length of the data processed by this cipher is not a multiple of428* block size429* @exception BadPaddingException if this cipher is in decryption mode,430* and (un)padding has been requested, but the decrypted data is not431* bounded by the appropriate padding bytes432*/433protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)434throws IllegalBlockSizeException, BadPaddingException {435byte[] out = core.doFinal(input, inputOffset, inputLen);436return out;437}438439/**440* Encrypts or decrypts data in a single-part operation,441* or finishes a multiple-part operation.442* The data is encrypted or decrypted, depending on how this cipher was443* initialized.444*445* <p>The first <code>inputLen</code> bytes in the <code>input</code>446* buffer, starting at <code>inputOffset</code>, and any input bytes that447* may have been buffered during a previous <code>update</code> operation,448* are processed, with padding (if requested) being applied.449* The result is stored in the <code>output</code> buffer, starting at450* <code>outputOffset</code>.451*452* <p>The cipher is reset to its initial state (uninitialized) after this453* call.454*455* @param input the input buffer456* @param inputOffset the offset in <code>input</code> where the input457* starts458* @param inputLen the input length459* @param output the buffer for the result460* @param outputOffset the offset in <code>output</code> where the result461* is stored462*463* @return the number of bytes stored in <code>output</code>464*465* @exception IllegalBlockSizeException if this cipher is a block cipher,466* no padding has been requested (only in encryption mode), and the total467* input length of the data processed by this cipher is not a multiple of468* block size469* @exception ShortBufferException if the given output buffer is too small470* to hold the result471* @exception BadPaddingException if this cipher is in decryption mode,472* and (un)padding has been requested, but the decrypted data is not473* bounded by the appropriate padding bytes474*/475protected int engineDoFinal(byte[] input, int inputOffset, int inputLen,476byte[] output, int outputOffset)477throws IllegalBlockSizeException, ShortBufferException,478BadPaddingException {479int outLen = core.doFinal(input, inputOffset, inputLen, output,480outputOffset);481return outLen;482}483484/**485* Returns the key size of the given key object.486*487* @param key the key object.488*489* @return the key size of the given key object.490*491* @exception InvalidKeyException if <code>key</code> is invalid.492*/493protected int engineGetKeySize(Key key) throws InvalidKeyException {494byte[] encoded = key.getEncoded();495Arrays.fill(encoded, (byte)0);496if (!AESCrypt.isKeySizeValid(encoded.length)) {497throw new InvalidKeyException("Invalid AES key length: " +498encoded.length + " bytes");499}500return Math.multiplyExact(encoded.length, 8);501}502503/**504* Wrap a key.505*506* @param key the key to be wrapped.507*508* @return the wrapped key.509*510* @exception IllegalBlockSizeException if this cipher is a block511* cipher, no padding has been requested, and the length of the512* encoding of the key to be wrapped is not a513* multiple of the block size.514*515* @exception InvalidKeyException if it is impossible or unsafe to516* wrap the key with this cipher (e.g., a hardware protected key is517* being passed to a software only cipher).518*/519protected byte[] engineWrap(Key key)520throws IllegalBlockSizeException, InvalidKeyException {521return core.wrap(key);522}523524/**525* Unwrap a previously wrapped key.526*527* @param wrappedKey the key to be unwrapped.528*529* @param wrappedKeyAlgorithm the algorithm the wrapped key is for.530*531* @param wrappedKeyType the type of the wrapped key.532* This is one of <code>Cipher.SECRET_KEY</code>,533* <code>Cipher.PRIVATE_KEY</code>, or <code>Cipher.PUBLIC_KEY</code>.534*535* @return the unwrapped key.536*537* @exception NoSuchAlgorithmException if no installed providers538* can create keys of type <code>wrappedKeyType</code> for the539* <code>wrappedKeyAlgorithm</code>.540*541* @exception InvalidKeyException if <code>wrappedKey</code> does not542* represent a wrapped key of type <code>wrappedKeyType</code> for543* the <code>wrappedKeyAlgorithm</code>.544*/545protected Key engineUnwrap(byte[] wrappedKey,546String wrappedKeyAlgorithm,547int wrappedKeyType)548throws InvalidKeyException, NoSuchAlgorithmException {549return core.unwrap(wrappedKey, wrappedKeyAlgorithm,550wrappedKeyType);551}552553/**554* Finalize crypto operation with ByteBuffers555*556* @param input the input ByteBuffer557* @param output the output ByteBuffer558*559* @return output length560* @throws ShortBufferException561* @throws IllegalBlockSizeException562* @throws BadPaddingException563*/564@Override565protected int engineDoFinal(ByteBuffer input, ByteBuffer output)566throws ShortBufferException, IllegalBlockSizeException,567BadPaddingException {568return super.engineDoFinal(input, output);569}570}571572573