Path: blob/master/src/java.base/share/classes/com/sun/crypto/provider/BlowfishCipher.java
41161 views
/*1* Copyright (c) 1998, 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 java.security.*;28import java.security.spec.*;29import java.util.Arrays;3031import sun.security.util.*;32import javax.crypto.*;33import javax.crypto.spec.*;34import javax.crypto.BadPaddingException;3536/**37* This class implements the Blowfish algorithm in its various modes38* (<code>ECB</code>, <code>CFB</code>, <code>OFB</code>, <code>CBC</code>,39* <code>PCBC</code>) and padding schemes (<code>PKCS5Padding</code>,40* <code>NoPadding</code>, <code>ISO10126Padding</code>).41*42* <p> Blowfish is a 64-bit block cipher with a variable-length key.43*44* @author Jan Luehe45*46*47* @see BlowfishCrypt48* @see CipherBlockChaining49* @see ElectronicCodeBook50* @see CipherFeedback51* @see OutputFeedback52*/5354public final class BlowfishCipher extends CipherSpi {5556/*57* internal CipherCore object which does the real work.58*/59private CipherCore core = null;6061/**62* Creates an instance of Blowfish cipher with default ECB mode and63* PKCS5Padding.64*/65public BlowfishCipher() {66core = new CipherCore(new BlowfishCrypt(),67BlowfishConstants.BLOWFISH_BLOCK_SIZE);68}6970/**71* Sets the mode of this cipher.72*73* @param mode the cipher mode74*75* @exception NoSuchAlgorithmException if the requested cipher mode does76* not exist77*/78protected void engineSetMode(String mode)79throws NoSuchAlgorithmException {80core.setMode(mode);81}8283/**84* Sets the padding mechanism of this cipher.85*86* @param paddingScheme the padding mechanism87*88* @exception NoSuchPaddingException if the requested padding mechanism89* does not exist90*/91protected void engineSetPadding(String paddingScheme)92throws NoSuchPaddingException {93core.setPadding(paddingScheme);94}9596/**97* Returns the block size (in bytes).98*99* @return the block size (in bytes), or 0 if the underlying algorithm is100* not a block cipher101*/102protected int engineGetBlockSize() {103return BlowfishConstants.BLOWFISH_BLOCK_SIZE;104}105106/**107* Returns the length in bytes that an output buffer would need to be in108* order to hold the result of the next <code>update</code> or109* <code>doFinal</code> operation, given the input length110* <code>inputLen</code> (in bytes).111*112* <p>This call takes into account any unprocessed (buffered) data from a113* previous <code>update</code> call, and padding.114*115* <p>The actual output length of the next <code>update</code> or116* <code>doFinal</code> call may be smaller than the length returned by117* this method.118*119* @param inputLen the input length (in bytes)120*121* @return the required output buffer size (in bytes)122*/123protected int engineGetOutputSize(int inputLen) {124return core.getOutputSize(inputLen);125}126127/**128* Returns the initialization vector (IV) in a new buffer.129*130* <p>This is useful in the case where a random IV has been created131* (see <a href = "#init">init</a>),132* or in the context of password-based encryption or133* decryption, where the IV is derived from a user-supplied password.134*135* @return the initialization vector in a new buffer, or null if the136* underlying algorithm does not use an IV, or if the IV has not yet137* been set.138*/139protected byte[] engineGetIV() {140return core.getIV();141}142143/**144* Returns the parameters used with this cipher.145*146* <p>The returned parameters may be the same that were used to initialize147* this cipher, or may contain the default set of parameters or a set of148* randomly generated parameters used by the underlying cipher149* implementation (provided that the underlying cipher implementation150* uses a default set of parameters or creates new parameters if it needs151* parameters but was not initialized with any).152*153* @return the parameters used with this cipher, or null if this cipher154* does not use any parameters.155*/156protected AlgorithmParameters engineGetParameters() {157return core.getParameters("Blowfish");158}159160/**161* Initializes this cipher with a key and a source of randomness.162*163* <p>The cipher is initialized for one of the following four operations:164* encryption, decryption, key wrapping or key unwrapping, depending on165* the value of <code>opmode</code>.166*167* <p>If this cipher requires an initialization vector (IV), it will get168* it from <code>random</code>.169* This behaviour should only be used in encryption or key wrapping170* mode, however.171* When initializing a cipher that requires an IV for decryption or172* key unwrapping, the IV173* (same IV that was used for encryption or key wrapping) must be provided174* explicitly as a175* parameter, in order to get the correct result.176*177* <p>This method also cleans existing buffer and other related state178* information.179*180* @param opmode the operation mode of this cipher (this is one of181* the following:182* <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,183* <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)184* @param key the secret key185* @param random the source of randomness186*187* @exception InvalidKeyException if the given key is inappropriate for188* initializing this cipher189*/190protected void engineInit(int opmode, Key key, SecureRandom random)191throws InvalidKeyException {192core.init(opmode, key, random);193}194195/**196* Initializes this cipher with a key, a set of197* algorithm parameters, and a source of randomness.198*199* <p>The cipher is initialized for one of the following four operations:200* encryption, decryption, key wrapping or key unwrapping, depending on201* the value of <code>opmode</code>.202*203* <p>If this cipher (including its underlying feedback or padding scheme)204* requires any random bytes, it will get them from <code>random</code>.205*206* @param opmode the operation mode of this cipher (this is one of207* the following:208* <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>,209* <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)210* @param key the encryption key211* @param params the algorithm parameters212* @param random the source of randomness213*214* @exception InvalidKeyException if the given key is inappropriate for215* initializing this cipher216* @exception InvalidAlgorithmParameterException if the given algorithm217* parameters are inappropriate for this cipher218*/219protected void engineInit(int opmode, Key key,220AlgorithmParameterSpec params,221SecureRandom random)222throws InvalidKeyException, InvalidAlgorithmParameterException {223core.init(opmode, key, params, random);224}225226protected void engineInit(int opmode, Key key,227AlgorithmParameters params,228SecureRandom random)229throws InvalidKeyException, InvalidAlgorithmParameterException {230core.init(opmode, key, params, random);231}232233/**234* Continues a multiple-part encryption or decryption operation235* (depending on how this cipher was initialized), processing another data236* part.237*238* <p>The first <code>inputLen</code> bytes in the <code>input</code>239* buffer, starting at <code>inputOffset</code>, are processed, and the240* result is stored in a new buffer.241*242* @param input the input buffer243* @param inputOffset the offset in <code>input</code> where the input244* starts245* @param inputLen the input length246*247* @return the new buffer with the result248*249* @exception IllegalStateException if this cipher is in a wrong state250* (e.g., has not been initialized)251*/252protected byte[] engineUpdate(byte[] input, int inputOffset,253int inputLen) {254return core.update(input, inputOffset, inputLen);255}256257/**258* Continues a multiple-part encryption or decryption operation259* (depending on how this cipher was initialized), processing another data260* part.261*262* <p>The first <code>inputLen</code> bytes in the <code>input</code>263* buffer, starting at <code>inputOffset</code>, are processed, and the264* result is stored in the <code>output</code> buffer, starting at265* <code>outputOffset</code>.266*267* @param input the input buffer268* @param inputOffset the offset in <code>input</code> where the input269* starts270* @param inputLen the input length271* @param output the buffer for the result272* @param outputOffset the offset in <code>output</code> where the result273* is stored274*275* @return the number of bytes stored in <code>output</code>276*277* @exception ShortBufferException if the given output buffer is too small278* to hold the result279*/280protected int engineUpdate(byte[] input, int inputOffset, int inputLen,281byte[] output, int outputOffset)282throws ShortBufferException {283return core.update(input, inputOffset, inputLen, output,284outputOffset);285}286287/**288* Encrypts or decrypts data in a single-part operation,289* or finishes a multiple-part operation.290* The data is encrypted or decrypted, depending on how this cipher was291* initialized.292*293* <p>The first <code>inputLen</code> bytes in the <code>input</code>294* buffer, starting at <code>inputOffset</code>, and any input bytes that295* may have been buffered during a previous <code>update</code> operation,296* are processed, with padding (if requested) being applied.297* The result is stored in a new buffer.298*299* <p>The cipher is reset to its initial state (uninitialized) after this300* call.301*302* @param input the input buffer303* @param inputOffset the offset in <code>input</code> where the input304* starts305* @param inputLen the input length306*307* @return the new buffer with the result308*309* @exception IllegalBlockSizeException if this cipher is a block cipher,310* no padding has been requested (only in encryption mode), and the total311* input length of the data processed by this cipher is not a multiple of312* block size313* @exception BadPaddingException if this cipher is in decryption mode,314* and (un)padding has been requested, but the decrypted data is not315* bounded by the appropriate padding bytes316*/317protected byte[] engineDoFinal(byte[] input, int inputOffset,318int inputLen)319throws IllegalBlockSizeException, BadPaddingException {320return core.doFinal(input, inputOffset, inputLen);321}322323/**324* Encrypts or decrypts data in a single-part operation,325* or finishes a multiple-part operation.326* The data is encrypted or decrypted, depending on how this cipher was327* initialized.328*329* <p>The first <code>inputLen</code> bytes in the <code>input</code>330* buffer, starting at <code>inputOffset</code>, and any input bytes that331* may have been buffered during a previous <code>update</code> operation,332* are processed, with padding (if requested) being applied.333* The result is stored in the <code>output</code> buffer, starting at334* <code>outputOffset</code>.335*336* <p>The cipher is reset to its initial state (uninitialized) after this337* call.338*339* @param input the input buffer340* @param inputOffset the offset in <code>input</code> where the input341* starts342* @param inputLen the input length343* @param output the buffer for the result344* @param outputOffset the offset in <code>output</code> where the result345* is stored346*347* @return the number of bytes stored in <code>output</code>348*349* @exception IllegalBlockSizeException if this cipher is a block cipher,350* no padding has been requested (only in encryption mode), and the total351* input length of the data processed by this cipher is not a multiple of352* block size353* @exception ShortBufferException if the given output buffer is too small354* to hold the result355* @exception BadPaddingException if this cipher is in decryption mode,356* and (un)padding has been requested, but the decrypted data is not357* bounded by the appropriate padding bytes358*/359protected int engineDoFinal(byte[] input, int inputOffset, int inputLen,360byte[] output, int outputOffset)361throws IllegalBlockSizeException, ShortBufferException,362BadPaddingException {363return core.doFinal(input, inputOffset, inputLen, output,364outputOffset);365}366367/**368* Returns the key size of the given key object.369*370* @param key the key object.371*372* @return the key size of the given key object.373*374* @exception InvalidKeyException if <code>key</code> is invalid.375*/376protected int engineGetKeySize(Key key) throws InvalidKeyException {377byte[] encodedKey = key.getEncoded();378Arrays.fill(encodedKey, (byte)0);379return Math.multiplyExact(encodedKey.length, 8);380}381382/**383* Wrap a key.384*385* @param key the key to be wrapped.386*387* @return the wrapped key.388*389* @exception IllegalBlockSizeException if this cipher is a block390* cipher, no padding has been requested, and the length of the391* encoding of the key to be wrapped is not a392* multiple of the block size.393*394* @exception InvalidKeyException if it is impossible or unsafe to395* wrap the key with this cipher (e.g., a hardware protected key is396* being passed to a software only cipher).397*/398protected byte[] engineWrap(Key key)399throws IllegalBlockSizeException, InvalidKeyException {400return core.wrap(key);401}402403/**404* Unwrap a previously wrapped key.405*406* @param wrappedKey the key to be unwrapped.407*408* @param wrappedKeyAlgorithm the algorithm the wrapped key is for.409*410* @param wrappedKeyType the type of the wrapped key.411* This is one of <code>Cipher.SECRET_KEY</code>,412* <code>Cipher.PRIVATE_KEY</code>, or <code>Cipher.PUBLIC_KEY</code>.413*414* @return the unwrapped key.415*416* @exception NoSuchAlgorithmException if no installed providers417* can create keys of type <code>wrappedKeyType</code> for the418* <code>wrappedKeyAlgorithm</code>.419*420* @exception InvalidKeyException if <code>wrappedKey</code> does not421* represent a wrapped key of type <code>wrappedKeyType</code> for422* the <code>wrappedKeyAlgorithm</code>.423*/424protected Key engineUnwrap(byte[] wrappedKey,425String wrappedKeyAlgorithm,426int wrappedKeyType)427throws InvalidKeyException, NoSuchAlgorithmException {428return core.unwrap(wrappedKey, wrappedKeyAlgorithm,429wrappedKeyType);430}431}432433434