8179098: Crypto AES/ECB encryption/decryption performance regression (introduced in jdk9b73)

Do bounds check per encryption/decryption call instead of per block

Reviewed-by: ascarpino, redestad
This commit is contained in:
Valerie Peng 2018-07-13 02:36:42 +00:00
parent b8d80042d7
commit b0af57a018
9 changed files with 137 additions and 73 deletions

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -39,7 +39,6 @@ package com.sun.crypto.provider;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.util.Arrays; import java.util.Arrays;
import java.util.Objects;
import jdk.internal.HotSpotIntrinsicCandidate; import jdk.internal.HotSpotIntrinsicCandidate;
@ -351,8 +350,8 @@ final class AESCrypt extends SymmetricCipher implements AESConstants
*/ */
void encryptBlock(byte[] in, int inOffset, void encryptBlock(byte[] in, int inOffset,
byte[] out, int outOffset) { byte[] out, int outOffset) {
Objects.checkFromIndexSize(inOffset, AES_BLOCK_SIZE, in.length); // Array bound checks are done in caller code, i.e.
Objects.checkFromIndexSize(outOffset, AES_BLOCK_SIZE, out.length); // FeedbackCipher.encrypt/decrypt(...) to improve performance.
implEncryptBlock(in, inOffset, out, outOffset); implEncryptBlock(in, inOffset, out, outOffset);
} }
@ -430,8 +429,8 @@ final class AESCrypt extends SymmetricCipher implements AESConstants
*/ */
void decryptBlock(byte[] in, int inOffset, void decryptBlock(byte[] in, int inOffset,
byte[] out, int outOffset) { byte[] out, int outOffset) {
Objects.checkFromIndexSize(inOffset, AES_BLOCK_SIZE, in.length); // Array bound checks are done in caller code, i.e.
Objects.checkFromIndexSize(outOffset, AES_BLOCK_SIZE, out.length); // FeedbackCipher.encrypt/decrypt(...) to improve performance.
implDecryptBlock(in, inOffset, out, outOffset); implDecryptBlock(in, inOffset, out, outOffset);
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -30,6 +30,7 @@ import java.security.ProviderException;
import java.util.Objects; import java.util.Objects;
import jdk.internal.HotSpotIntrinsicCandidate; import jdk.internal.HotSpotIntrinsicCandidate;
import sun.security.util.ArrayUtil;
/** /**
@ -145,9 +146,9 @@ class CipherBlockChaining extends FeedbackCipher {
if (plainLen <= 0) { if (plainLen <= 0) {
return plainLen; return plainLen;
} }
cryptBlockSizeCheck(plainLen); ArrayUtil.blockSizeCheck(plainLen, blockSize);
cryptNullAndBoundsCheck(plain, plainOffset, plainLen); ArrayUtil.nullAndBoundsCheck(plain, plainOffset, plainLen);
cryptNullAndBoundsCheck(cipher, cipherOffset, plainLen); ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, plainLen);
return implEncrypt(plain, plainOffset, plainLen, return implEncrypt(plain, plainOffset, plainLen,
cipher, cipherOffset); cipher, cipherOffset);
} }
@ -196,9 +197,9 @@ class CipherBlockChaining extends FeedbackCipher {
if (cipherLen <= 0) { if (cipherLen <= 0) {
return cipherLen; return cipherLen;
} }
cryptBlockSizeCheck(cipherLen); ArrayUtil.blockSizeCheck(cipherLen, blockSize);
cryptNullAndBoundsCheck(cipher, cipherOffset, cipherLen); ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, cipherLen);
cryptNullAndBoundsCheck(plain, plainOffset, cipherLen); ArrayUtil.nullAndBoundsCheck(plain, plainOffset, cipherLen);
return implDecrypt(cipher, cipherOffset, cipherLen, plain, plainOffset); return implDecrypt(cipher, cipherOffset, cipherLen, plain, plainOffset);
} }
@ -218,23 +219,4 @@ class CipherBlockChaining extends FeedbackCipher {
} }
return cipherLen; return cipherLen;
} }
private void cryptBlockSizeCheck(int len) {
if ((len % blockSize) != 0) {
throw new ProviderException("Internal error in input buffering");
}
}
private static void cryptNullAndBoundsCheck(byte[] array, int offset, int len) {
Objects.requireNonNull(array);
if (offset < 0 || offset >= array.length) {
throw new ArrayIndexOutOfBoundsException(offset);
}
int endIndex = offset + len - 1;
if (endIndex < 0 || endIndex >= array.length) {
throw new ArrayIndexOutOfBoundsException(endIndex);
}
}
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -27,6 +27,7 @@ package com.sun.crypto.provider;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.ProviderException; import java.security.ProviderException;
import sun.security.util.ArrayUtil;
/** /**
* This class represents ciphers in cipher-feedback (CFB) mode. * This class represents ciphers in cipher-feedback (CFB) mode.
@ -149,9 +150,9 @@ final class CipherFeedback extends FeedbackCipher {
*/ */
int encrypt(byte[] plain, int plainOffset, int plainLen, int encrypt(byte[] plain, int plainOffset, int plainLen,
byte[] cipher, int cipherOffset) { byte[] cipher, int cipherOffset) {
if ((plainLen % numBytes) != 0) { ArrayUtil.blockSizeCheck(plainLen, numBytes);
throw new ProviderException("Internal error in input buffering"); ArrayUtil.nullAndBoundsCheck(plain, plainOffset, plainLen);
} ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, plainLen);
int nShift = blockSize - numBytes; int nShift = blockSize - numBytes;
int loopCount = plainLen / numBytes; int loopCount = plainLen / numBytes;
@ -225,9 +226,10 @@ final class CipherFeedback extends FeedbackCipher {
*/ */
int decrypt(byte[] cipher, int cipherOffset, int cipherLen, int decrypt(byte[] cipher, int cipherOffset, int cipherLen,
byte[] plain, int plainOffset) { byte[] plain, int plainOffset) {
if ((cipherLen % numBytes) != 0) {
throw new ProviderException("Internal error in input buffering"); ArrayUtil.blockSizeCheck(cipherLen, numBytes);
} ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, cipherLen);
ArrayUtil.nullAndBoundsCheck(plain, plainOffset, cipherLen);
int nShift = blockSize - numBytes; int nShift = blockSize - numBytes;
int loopCount = cipherLen / numBytes; int loopCount = cipherLen / numBytes;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -26,9 +26,9 @@
package com.sun.crypto.provider; package com.sun.crypto.provider;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.util.Objects;
import jdk.internal.HotSpotIntrinsicCandidate; import jdk.internal.HotSpotIntrinsicCandidate;
import sun.security.util.ArrayUtil;
/** /**
* This class represents ciphers in counter (CTR) mode. * This class represents ciphers in counter (CTR) mode.
@ -175,8 +175,9 @@ class CounterMode extends FeedbackCipher {
if (len == 0) { if (len == 0) {
return 0; return 0;
} }
Objects.checkFromIndexSize(inOff, len, in.length);
Objects.checkFromIndexSize(outOff, len, out.length); ArrayUtil.nullAndBoundsCheck(in, inOff, len);
ArrayUtil.nullAndBoundsCheck(out, outOff, len);
return implCrypt(in, inOff, len, out, outOff); return implCrypt(in, inOff, len, out, outOff);
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -27,6 +27,7 @@ package com.sun.crypto.provider;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.ProviderException; import java.security.ProviderException;
import sun.security.util.ArrayUtil;
/** /**
* This class represents ciphers in electronic codebook (ECB) mode. * This class represents ciphers in electronic codebook (ECB) mode.
@ -112,9 +113,10 @@ final class ElectronicCodeBook extends FeedbackCipher {
* @return the length of the encrypted data * @return the length of the encrypted data
*/ */
int encrypt(byte[] in, int inOff, int len, byte[] out, int outOff) { int encrypt(byte[] in, int inOff, int len, byte[] out, int outOff) {
if ((len % blockSize) != 0) { ArrayUtil.blockSizeCheck(len, blockSize);
throw new ProviderException("Internal error in input buffering"); ArrayUtil.nullAndBoundsCheck(in, inOff, len);
} ArrayUtil.nullAndBoundsCheck(out, outOff, len);
for (int i = len; i >= blockSize; i -= blockSize) { for (int i = len; i >= blockSize; i -= blockSize) {
embeddedCipher.encryptBlock(in, inOff, out, outOff); embeddedCipher.encryptBlock(in, inOff, out, outOff);
inOff += blockSize; inOff += blockSize;
@ -141,9 +143,10 @@ final class ElectronicCodeBook extends FeedbackCipher {
* @return the length of the decrypted data * @return the length of the decrypted data
*/ */
int decrypt(byte[] in, int inOff, int len, byte[] out, int outOff) { int decrypt(byte[] in, int inOff, int len, byte[] out, int outOff) {
if ((len % blockSize) != 0) { ArrayUtil.blockSizeCheck(len, blockSize);
throw new ProviderException("Internal error in input buffering"); ArrayUtil.nullAndBoundsCheck(in, inOff, len);
} ArrayUtil.nullAndBoundsCheck(out, outOff, len);
for (int i = len; i >= blockSize; i -= blockSize) { for (int i = len; i >= blockSize; i -= blockSize) {
embeddedCipher.decryptBlock(in, inOff, out, outOff); embeddedCipher.decryptBlock(in, inOff, out, outOff);
inOff += blockSize; inOff += blockSize;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -30,6 +30,8 @@ import java.io.*;
import java.security.*; import java.security.*;
import javax.crypto.*; import javax.crypto.*;
import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE; import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE;
import sun.security.util.ArrayUtil;
/** /**
* This class represents ciphers in GaloisCounter (GCM) mode. * This class represents ciphers in GaloisCounter (GCM) mode.
@ -406,8 +408,8 @@ final class GaloisCounterMode extends FeedbackCipher {
/** /**
* Performs encryption operation. * Performs encryption operation.
* *
* <p>The input plain text <code>in</code>, starting at <code>inOff</code> * <p>The input plain text <code>in</code>, starting at <code>inOfs</code>
* and ending at <code>(inOff + len - 1)</code>, is encrypted. The result * and ending at <code>(inOfs + len - 1)</code>, is encrypted. The result
* is stored in <code>out</code>, starting at <code>outOfs</code>. * is stored in <code>out</code>, starting at <code>outOfs</code>.
* *
* @param in the buffer with the input data to be encrypted * @param in the buffer with the input data to be encrypted
@ -420,18 +422,21 @@ final class GaloisCounterMode extends FeedbackCipher {
* @return the number of bytes placed into the <code>out</code> buffer * @return the number of bytes placed into the <code>out</code> buffer
*/ */
int encrypt(byte[] in, int inOfs, int len, byte[] out, int outOfs) { int encrypt(byte[] in, int inOfs, int len, byte[] out, int outOfs) {
if ((len % blockSize) != 0) { ArrayUtil.blockSizeCheck(len, blockSize);
throw new ProviderException("Internal error in input buffering");
}
checkDataLength(processed, len); checkDataLength(processed, len);
processAAD(); processAAD();
if (len > 0) { if (len > 0) {
ArrayUtil.nullAndBoundsCheck(in, inOfs, len);
ArrayUtil.nullAndBoundsCheck(out, outOfs, len);
gctrPAndC.update(in, inOfs, len, out, outOfs); gctrPAndC.update(in, inOfs, len, out, outOfs);
processed += len; processed += len;
ghashAllToS.update(out, outOfs, len); ghashAllToS.update(out, outOfs, len);
} }
return len; return len;
} }
@ -451,7 +456,10 @@ final class GaloisCounterMode extends FeedbackCipher {
throw new ShortBufferException throw new ShortBufferException
("Can't fit both data and tag into one buffer"); ("Can't fit both data and tag into one buffer");
} }
if (out.length - outOfs < (len + tagLenBytes)) { try {
ArrayUtil.nullAndBoundsCheck(out, outOfs,
(len + tagLenBytes));
} catch (ArrayIndexOutOfBoundsException aiobe) {
throw new ShortBufferException("Output buffer too small"); throw new ShortBufferException("Output buffer too small");
} }
@ -459,6 +467,8 @@ final class GaloisCounterMode extends FeedbackCipher {
processAAD(); processAAD();
if (len > 0) { if (len > 0) {
ArrayUtil.nullAndBoundsCheck(in, inOfs, len);
doLastBlock(in, inOfs, len, out, outOfs, true); doLastBlock(in, inOfs, len, out, outOfs, true);
} }
@ -492,9 +502,7 @@ final class GaloisCounterMode extends FeedbackCipher {
* @return the number of bytes placed into the <code>out</code> buffer * @return the number of bytes placed into the <code>out</code> buffer
*/ */
int decrypt(byte[] in, int inOfs, int len, byte[] out, int outOfs) { int decrypt(byte[] in, int inOfs, int len, byte[] out, int outOfs) {
if ((len % blockSize) != 0) { ArrayUtil.blockSizeCheck(len, blockSize);
throw new ProviderException("Internal error in input buffering");
}
checkDataLength(ibuffer.size(), len); checkDataLength(ibuffer.size(), len);
@ -504,6 +512,7 @@ final class GaloisCounterMode extends FeedbackCipher {
// store internally until decryptFinal is called because // store internally until decryptFinal is called because
// spec mentioned that only return recovered data after tag // spec mentioned that only return recovered data after tag
// is successfully verified // is successfully verified
ArrayUtil.nullAndBoundsCheck(in, inOfs, len);
ibuffer.write(in, inOfs, len); ibuffer.write(in, inOfs, len);
} }
return 0; return 0;
@ -532,22 +541,28 @@ final class GaloisCounterMode extends FeedbackCipher {
if (len < tagLenBytes) { if (len < tagLenBytes) {
throw new AEADBadTagException("Input too short - need tag"); throw new AEADBadTagException("Input too short - need tag");
} }
// do this check here can also catch the potential integer overflow // do this check here can also catch the potential integer overflow
// scenario for the subsequent output buffer capacity check. // scenario for the subsequent output buffer capacity check.
checkDataLength(ibuffer.size(), (len - tagLenBytes)); checkDataLength(ibuffer.size(), (len - tagLenBytes));
if (out.length - outOfs < ((ibuffer.size() + len) - tagLenBytes)) { try {
ArrayUtil.nullAndBoundsCheck(out, outOfs,
(ibuffer.size() + len) - tagLenBytes);
} catch (ArrayIndexOutOfBoundsException aiobe) {
throw new ShortBufferException("Output buffer too small"); throw new ShortBufferException("Output buffer too small");
} }
processAAD(); processAAD();
ArrayUtil.nullAndBoundsCheck(in, inOfs, len);
// get the trailing tag bytes from 'in' // get the trailing tag bytes from 'in'
byte[] tag = new byte[tagLenBytes]; byte[] tag = new byte[tagLenBytes];
System.arraycopy(in, inOfs + len - tagLenBytes, tag, 0, tagLenBytes); System.arraycopy(in, inOfs + len - tagLenBytes, tag, 0, tagLenBytes);
len -= tagLenBytes; len -= tagLenBytes;
if (len != 0) { if (len > 0) {
ibuffer.write(in, inOfs, len); ibuffer.write(in, inOfs, len);
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -27,6 +27,7 @@ package com.sun.crypto.provider;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.ProviderException; import java.security.ProviderException;
import sun.security.util.ArrayUtil;
/** /**
* This class represents ciphers in output-feedback (OFB) mode. * This class represents ciphers in output-feedback (OFB) mode.
@ -148,10 +149,10 @@ final class OutputFeedback extends FeedbackCipher {
*/ */
int encrypt(byte[] plain, int plainOffset, int plainLen, int encrypt(byte[] plain, int plainOffset, int plainLen,
byte[] cipher, int cipherOffset) { byte[] cipher, int cipherOffset) {
ArrayUtil.blockSizeCheck(plainLen, numBytes);
ArrayUtil.nullAndBoundsCheck(plain, plainOffset, plainLen);
ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, plainLen);
if ((plainLen % numBytes) != 0) {
throw new ProviderException("Internal error in input buffering");
}
int nShift = blockSize - numBytes; int nShift = blockSize - numBytes;
int loopCount = plainLen / numBytes; int loopCount = plainLen / numBytes;
@ -189,6 +190,9 @@ final class OutputFeedback extends FeedbackCipher {
*/ */
int encryptFinal(byte[] plain, int plainOffset, int plainLen, int encryptFinal(byte[] plain, int plainOffset, int plainLen,
byte[] cipher, int cipherOffset) { byte[] cipher, int cipherOffset) {
ArrayUtil.nullAndBoundsCheck(plain, plainOffset, plainLen);
ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, plainLen);
int oddBytes = plainLen % numBytes; int oddBytes = plainLen % numBytes;
int len = encrypt(plain, plainOffset, (plainLen - oddBytes), int len = encrypt(plain, plainOffset, (plainLen - oddBytes),
cipher, cipherOffset); cipher, cipherOffset);

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -27,6 +27,7 @@ package com.sun.crypto.provider;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.ProviderException; import java.security.ProviderException;
import sun.security.util.ArrayUtil;
/** /**
@ -136,9 +137,10 @@ final class PCBC extends FeedbackCipher {
int encrypt(byte[] plain, int plainOffset, int plainLen, int encrypt(byte[] plain, int plainOffset, int plainLen,
byte[] cipher, int cipherOffset) byte[] cipher, int cipherOffset)
{ {
if ((plainLen % blockSize) != 0) { ArrayUtil.blockSizeCheck(plainLen, blockSize);
throw new ProviderException("Internal error in input buffering"); ArrayUtil.nullAndBoundsCheck(plain, plainOffset, plainLen);
} ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, plainLen);
int i; int i;
int endIndex = plainOffset + plainLen; int endIndex = plainOffset + plainLen;
@ -176,9 +178,10 @@ final class PCBC extends FeedbackCipher {
int decrypt(byte[] cipher, int cipherOffset, int cipherLen, int decrypt(byte[] cipher, int cipherOffset, int cipherLen,
byte[] plain, int plainOffset) byte[] plain, int plainOffset)
{ {
if ((cipherLen % blockSize) != 0) { ArrayUtil.blockSizeCheck(cipherLen, blockSize);
throw new ProviderException("Internal error in input buffering"); ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, cipherLen);
} ArrayUtil.nullAndBoundsCheck(plain, plainOffset, cipherLen);
int i; int i;
int endIndex = cipherOffset + cipherLen; int endIndex = cipherOffset + cipherLen;

View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* 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.
*/
package sun.security.util;
import java.util.List;
import java.util.function.BiFunction;
import java.security.*;
import jdk.internal.util.Preconditions;
/**
* This class holds the various utility methods for array range checks.
*/
public final class ArrayUtil {
private static final BiFunction<String, List<Integer>,
ArrayIndexOutOfBoundsException> AIOOBE_SUPPLIER =
Preconditions.outOfBoundsExceptionFormatter
(ArrayIndexOutOfBoundsException::new);
public static void blockSizeCheck(int len, int blockSize) {
if ((len % blockSize) != 0) {
throw new ProviderException("Internal error in input buffering");
}
}
public static void nullAndBoundsCheck(byte[] array, int offset, int len) {
// NPE is thrown when array is null
Preconditions.checkFromIndexSize(offset, len, array.length, AIOOBE_SUPPLIER);
}
}