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