/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* This class handles bulk data enciphering/deciphering for each SSLv3
* message. This provides data confidentiality. Stream ciphers (such
* as RC4) don't need to do padding; block ciphers (e.g. DES) need it.
*
* Individual instances are obtained by calling the static method
* newCipherBox(), which should only be invoked by BulkCipher.newCipher().
*
* In RFC 2246, with bock ciphers in CBC mode, the Initialization
* Vector (IV) for the first record is generated with the other keys
* and secrets when the security parameters are set. The IV for
* subsequent records is the last ciphertext block from the previous
* record.
*
* In RFC 4346, the implicit Initialization Vector (IV) is replaced
* with an explicit IV to protect against CBC attacks. RFC 4346
* recommends two algorithms used to generated the per-record IV.
* The implementation uses the algorithm (2)(b), as described at
* section 6.2.3.2 of RFC 4346.
*
* The usage of IV in CBC block cipher can be illustrated in
* the following diagrams.
*
* (random)
* R P1 IV C1
* | | | |
* SIV---+ |-----+ |-... |----- |------
* | | | | | | | |
* +----+ | +----+ | +----+ | +----+ |
* | Ek | | + Ek + | | Dk | | | Dk | |
* +----+ | +----+ | +----+ | +----+ |
* | | | | | | | |
* |----| |----| SIV--+ |----| |-...
* | | | |
* IV C1 R P1
* (discard)
*
* CBC Encryption CBC Decryption
*
* NOTE that any ciphering involved in key exchange (e.g. with RSA) is
* handled separately.
*
* @author David Brownell
* @author Andreas Sterbenz
*/
final class CipherBox {
// A CipherBox that implements the identity operation
/* Class and subclass dynamic debugging support */
// the protocol version this cipher conforms to
// cipher object
/**
* Cipher blocksize, 0 for stream ciphers
*/
private int blockSize;
/**
* secure random
*/
/**
* Is the cipher of CBC mode?
*/
private final boolean isCBCMode;
/**
* Fixed masks of various block size, as the initial decryption IVs
* for TLS 1.1 or later.
*
* For performance, we do not use random IVs. As the initial decryption
* IVs will be discarded by TLS decryption processes, so the fixed masks
* do not hurt cryptographic strength.
*/
/**
* NULL cipherbox. Identity operation, no encryption.
*/
private CipherBox() {
this.isCBCMode = false;
}
/**
* Construct a new CipherBox using the cipher transformation.
*
* @exception NoSuchAlgorithmException if no appropriate JCE Cipher
* implementation could be found.
*/
boolean encrypt) throws NoSuchAlgorithmException {
try {
this.protocolVersion = protocolVersion;
}
/*
* RFC 4346 recommends two algorithms used to generated the
* per-record IV. The implementation uses the algorithm (2)(b),
* as described at section 6.2.3.2 of RFC 4346.
*
* As we don't care about the initial IV value for TLS 1.1 or
* later, so if the "iv" parameter is null, we use the default
* value generated by Cipher.init() for encryption, and a fixed
* mask for decryption.
*/
}
// Do not call getBlockSize until after init()
// otherwise we would disrupt JCE delayed provider selection
// some providers implement getBlockSize() incorrectly
if (blockSize == 1) {
blockSize = 0;
}
} catch (NoSuchAlgorithmException e) {
throw e;
} catch (Exception e) {
throw new NoSuchAlgorithmException
("Could not create cipher " + bulkCipher, e);
} catch (ExceptionInInitializerError e) {
throw new NoSuchAlgorithmException
("Could not create cipher " + bulkCipher, e);
}
}
/*
* Factory method to obtain a new CipherBox object.
*/
boolean encrypt) throws NoSuchAlgorithmException {
}
return NULL;
} else {
}
}
/*
* Get a fixed mask, as the initial decryption IVs for TLS 1.1 or later.
*/
}
}
return iv;
}
/*
* Encrypts a block of data, returning the size of the
* resulting block.
*/
return len;
}
try {
if (blockSize != 0) {
// TLSv1.1 needs a IV block
// generate a random number
// move forward the plaintext
// prefix the plaintext
}
}
try {
"Padded plaintext before ENCRYPTION: len = "
+ len);
} catch (IOException e) { }
}
// catch BouncyCastle buffering error
throw new RuntimeException("Cipher buffering error " +
}
return newLen;
} catch (ShortBufferException e) {
throw new ArrayIndexOutOfBoundsException(e.toString());
}
}
/*
* Encrypts a ByteBuffer block of data, returning the size of the
* resulting block.
*
* The byte buffers position and limit initially define the amount
* to encrypt. On return, the position and limit are
* because of the added padding bytes.
*/
return len;
}
try {
if (blockSize != 0) {
// TLSv1.1 needs a IV block
// generate a random number
// move forward the plaintext
} else {
}
// prefix the plaintext
}
}
try {
"Padded plaintext before ENCRYPTION: len = "
+ len);
} catch (IOException e) { }
/*
* reset back to beginning
*/
}
/*
* Encrypt "in-place". This does not add its own padding.
*/
throw new RuntimeException("bytebuffer padding error");
}
// catch BouncyCastle buffering error
throw new RuntimeException("Cipher buffering error " +
}
return newLen;
} catch (ShortBufferException e) {
throw exc;
}
}
/*
* Decrypts a block of data, returning the size of the
* resulting block if padding was required.
*
* For SSLv3 and TLSv1.0, with block ciphers in CBC mode the
* Initialization Vector (IV) for the first record is generated by
* the handshake protocol, the IV for subsequent records is the
* last ciphertext block from the previous record.
*
* From TLSv1.1, the implicit IV is replaced with an explicit IV to
* protect against CBC attacks.
*
* Differentiating between bad_record_mac and decryption_failed alerts
* may permit certain attacks against CBC mode. It is preferable to
* uniformly use the bad_record_mac alert to hide the specific type of
* the error.
*/
int tagLen) throws BadPaddingException {
return len;
}
try {
// catch BouncyCastle buffering error
throw new RuntimeException("Cipher buffering error " +
}
try {
"Padded plaintext after DECRYPTION: len = "
+ newLen);
} catch (IOException e) { }
}
if (blockSize != 0) {
throw new BadPaddingException("invalid explicit IV");
}
// discards the first cipher block, the IV component.
}
}
return newLen;
} catch (ShortBufferException e) {
throw new ArrayIndexOutOfBoundsException(e.toString());
}
}
/*
* Decrypts a block of data, returning the size of the
* resulting block if padding was required. position and limit
* limit and new limit may be different, given we may
* have stripped off some padding bytes.
*
* @see decrypt(byte[], int, int)
*/
return len;
}
try {
/*
* Decrypt "in-place".
*/
// catch BouncyCastle buffering error
throw new RuntimeException("Cipher buffering error " +
}
try {
"Padded plaintext after DECRYPTION: len = "
+ newLen);
} catch (IOException e) { }
}
/*
* Remove the block padding.
*/
if (blockSize != 0) {
throw new BadPaddingException("invalid explicit IV");
}
// discards the first cipher block, the IV component.
} else {
}
// reset the position to the end of the decrypted data
}
}
return newLen;
} catch (ShortBufferException e) {
throw exc;
}
}
int blockSize) {
byte pad;
int i;
}
throw new IllegalArgumentException("no space to pad buffer");
}
/*
* TLS version of the padding works for both SSLv3 and TLSv1
*/
}
return newlen;
}
/*
* Apply the padding to the buffer.
*
* Limit is advanced to the new buffer length.
* Position is equal to limit.
*/
byte pad;
int i;
}
/*
* Update the limit to what will be padded.
*/
/*
* TLS version of the padding works for both SSLv3 and TLSv1
*/
}
return newlen;
}
/*
* A constant-time check of the padding.
*
* NOTE that we are checking both the padding and the padLen bytes here.
*
* The caller MUST ensure that the len parameter is a positive number.
*/
private static int[] checkPadding(
if (len <= 0) {
throw new RuntimeException("padding len must be positive");
}
// An array of hits is used to prevent Hotspot optimization for
// the purpose of a constant-time check.
for (int i = 0; i <= 256;) {
} else {
}
}
}
return results;
}
/*
* A constant-time check of the padding.
*
* NOTE that we are checking both the padding and the padLen bytes here.
*
* The caller MUST ensure that the bb parameter has remaining.
*/
if (!bb.hasRemaining()) {
throw new RuntimeException("hasRemaining() must be positive");
}
// An array of hits is used to prevent Hotspot optimization for
// the purpose of a constant-time check.
} else {
}
}
}
return results;
}
/*
* Typical TLS padding format for a 64 bit block cipher is as follows:
* xx xx xx xx xx xx xx 00
* xx xx xx xx xx xx 01 01
* ...
* xx 06 06 06 06 06 06 06
* 07 07 07 07 07 07 07 07
* TLS also allows any amount of padding from 1 and 256 bytes as long
* as it makes the data a multiple of the block size
*/
// last byte is length byte (i.e. actual padding length - 1)
// If the buffer is not long enough to contain the padding plus
// a MAC tag, do a dummy constant-time padding check.
//
// Note that it is a dummy check, so we won't care about what is
// the actual padding data.
}
// The padding data should be filled with the padding length value.
throw new BadPaddingException("Invalid TLS padding data");
}
} else { // SSLv3
// SSLv3 requires 0 <= length byte < block size
// some implementations do 1 <= length byte <= block size,
// so accept that as well
// v3 does not require any particular value for the other bytes
throw new BadPaddingException("Invalid SSLv3 padding");
}
}
return newLen;
}
/*
*/
// last byte is length byte (i.e. actual padding length - 1)
// If the buffer is not long enough to contain the padding plus
// a MAC tag, do a dummy constant-time padding check.
//
// Note that it is a dummy check, so we won't care about what is
// the actual padding data.
}
// The padding data should be filled with the padding length value.
int[] results = checkPadding(
(byte)(padLen & 0xFF));
throw new BadPaddingException("Invalid TLS padding data");
}
} else { // SSLv3
// SSLv3 requires 0 <= length byte < block size
// some implementations do 1 <= length byte <= block size,
// so accept that as well
// v3 does not require any particular value for the other bytes
throw new BadPaddingException("Invalid SSLv3 padding");
}
}
/*
* Reset buffer limit to remove padding.
*/
return newLen;
}
/*
* Dispose of any intermediate state in the underlying cipher.
* For PKCS11 ciphers, this will release any attached sessions, and
* thus make finalization faster.
*/
void dispose() {
try {
// ignore return value.
}
} catch (GeneralSecurityException e) {
// swallow for now.
}
}
/*
* Does the cipher use CBC mode?
*
* @return true if the cipher use CBC mode, false otherwise.
*/
boolean isCBCMode() {
return isCBCMode;
}
/**
* Is the cipher null?
*
* @return true if the cipher is null, false otherwise.
*/
boolean isNullCipher() {
}
/**
* Sanity check the length of a fragment before decryption.
*
* In CBC mode, check that the fragment length is one or multiple times
* of the block size of the cipher suite, and is at least one (one is the
* smallest size of padding in CBC mode) bigger than the tag size of the
* MAC algorithm except the explicit IV size for TLS 1.1 or later.
*
* In non-CBC mode, check that the fragment length is not less than the
* tag size of the MAC algorithm.
*
* @return true if the length of a fragment matches above requirements
*/
if (!isCBCMode) {
return fragmentLen >= tagLen;
}
}
return (fragmentLen >= minimal);
}
return false;
}
}