mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 14:24:46 +02:00
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:
parent
b8d80042d7
commit
b0af57a018
9 changed files with 137 additions and 73 deletions
|
@ -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.
|
||||
*
|
||||
* 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.MessageDigest;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
|
||||
|
@ -351,8 +350,8 @@ final class AESCrypt extends SymmetricCipher implements AESConstants
|
|||
*/
|
||||
void encryptBlock(byte[] in, int inOffset,
|
||||
byte[] out, int outOffset) {
|
||||
Objects.checkFromIndexSize(inOffset, AES_BLOCK_SIZE, in.length);
|
||||
Objects.checkFromIndexSize(outOffset, AES_BLOCK_SIZE, out.length);
|
||||
// Array bound checks are done in caller code, i.e.
|
||||
// FeedbackCipher.encrypt/decrypt(...) to improve performance.
|
||||
implEncryptBlock(in, inOffset, out, outOffset);
|
||||
}
|
||||
|
||||
|
@ -430,8 +429,8 @@ final class AESCrypt extends SymmetricCipher implements AESConstants
|
|||
*/
|
||||
void decryptBlock(byte[] in, int inOffset,
|
||||
byte[] out, int outOffset) {
|
||||
Objects.checkFromIndexSize(inOffset, AES_BLOCK_SIZE, in.length);
|
||||
Objects.checkFromIndexSize(outOffset, AES_BLOCK_SIZE, out.length);
|
||||
// Array bound checks are done in caller code, i.e.
|
||||
// FeedbackCipher.encrypt/decrypt(...) to improve performance.
|
||||
implDecryptBlock(in, inOffset, out, outOffset);
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
* 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 jdk.internal.HotSpotIntrinsicCandidate;
|
||||
import sun.security.util.ArrayUtil;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -145,9 +146,9 @@ class CipherBlockChaining extends FeedbackCipher {
|
|||
if (plainLen <= 0) {
|
||||
return plainLen;
|
||||
}
|
||||
cryptBlockSizeCheck(plainLen);
|
||||
cryptNullAndBoundsCheck(plain, plainOffset, plainLen);
|
||||
cryptNullAndBoundsCheck(cipher, cipherOffset, plainLen);
|
||||
ArrayUtil.blockSizeCheck(plainLen, blockSize);
|
||||
ArrayUtil.nullAndBoundsCheck(plain, plainOffset, plainLen);
|
||||
ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, plainLen);
|
||||
return implEncrypt(plain, plainOffset, plainLen,
|
||||
cipher, cipherOffset);
|
||||
}
|
||||
|
@ -196,9 +197,9 @@ class CipherBlockChaining extends FeedbackCipher {
|
|||
if (cipherLen <= 0) {
|
||||
return cipherLen;
|
||||
}
|
||||
cryptBlockSizeCheck(cipherLen);
|
||||
cryptNullAndBoundsCheck(cipher, cipherOffset, cipherLen);
|
||||
cryptNullAndBoundsCheck(plain, plainOffset, cipherLen);
|
||||
ArrayUtil.blockSizeCheck(cipherLen, blockSize);
|
||||
ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, cipherLen);
|
||||
ArrayUtil.nullAndBoundsCheck(plain, plainOffset, cipherLen);
|
||||
return implDecrypt(cipher, cipherOffset, cipherLen, plain, plainOffset);
|
||||
}
|
||||
|
||||
|
@ -218,23 +219,4 @@ class CipherBlockChaining extends FeedbackCipher {
|
|||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
* 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.ProviderException;
|
||||
import sun.security.util.ArrayUtil;
|
||||
|
||||
/**
|
||||
* 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,
|
||||
byte[] cipher, int cipherOffset) {
|
||||
if ((plainLen % numBytes) != 0) {
|
||||
throw new ProviderException("Internal error in input buffering");
|
||||
}
|
||||
ArrayUtil.blockSizeCheck(plainLen, numBytes);
|
||||
ArrayUtil.nullAndBoundsCheck(plain, plainOffset, plainLen);
|
||||
ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, plainLen);
|
||||
|
||||
int nShift = blockSize - numBytes;
|
||||
int loopCount = plainLen / numBytes;
|
||||
|
@ -225,9 +226,10 @@ final class CipherFeedback extends FeedbackCipher {
|
|||
*/
|
||||
int decrypt(byte[] cipher, int cipherOffset, int cipherLen,
|
||||
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 loopCount = cipherLen / numBytes;
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -26,9 +26,9 @@
|
|||
package com.sun.crypto.provider;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
import sun.security.util.ArrayUtil;
|
||||
|
||||
/**
|
||||
* This class represents ciphers in counter (CTR) mode.
|
||||
|
@ -175,8 +175,9 @@ class CounterMode extends FeedbackCipher {
|
|||
if (len == 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
* 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.ProviderException;
|
||||
import sun.security.util.ArrayUtil;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
int encrypt(byte[] in, int inOff, int len, byte[] out, int outOff) {
|
||||
if ((len % blockSize) != 0) {
|
||||
throw new ProviderException("Internal error in input buffering");
|
||||
}
|
||||
ArrayUtil.blockSizeCheck(len, blockSize);
|
||||
ArrayUtil.nullAndBoundsCheck(in, inOff, len);
|
||||
ArrayUtil.nullAndBoundsCheck(out, outOff, len);
|
||||
|
||||
for (int i = len; i >= blockSize; i -= blockSize) {
|
||||
embeddedCipher.encryptBlock(in, inOff, out, outOff);
|
||||
inOff += blockSize;
|
||||
|
@ -141,9 +143,10 @@ final class ElectronicCodeBook extends FeedbackCipher {
|
|||
* @return the length of the decrypted data
|
||||
*/
|
||||
int decrypt(byte[] in, int inOff, int len, byte[] out, int outOff) {
|
||||
if ((len % blockSize) != 0) {
|
||||
throw new ProviderException("Internal error in input buffering");
|
||||
}
|
||||
ArrayUtil.blockSizeCheck(len, blockSize);
|
||||
ArrayUtil.nullAndBoundsCheck(in, inOff, len);
|
||||
ArrayUtil.nullAndBoundsCheck(out, outOff, len);
|
||||
|
||||
for (int i = len; i >= blockSize; i -= blockSize) {
|
||||
embeddedCipher.decryptBlock(in, inOff, out, outOff);
|
||||
inOff += blockSize;
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -30,6 +30,8 @@ import java.io.*;
|
|||
import java.security.*;
|
||||
import javax.crypto.*;
|
||||
import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE;
|
||||
import sun.security.util.ArrayUtil;
|
||||
|
||||
|
||||
/**
|
||||
* This class represents ciphers in GaloisCounter (GCM) mode.
|
||||
|
@ -406,8 +408,8 @@ final class GaloisCounterMode extends FeedbackCipher {
|
|||
/**
|
||||
* Performs encryption operation.
|
||||
*
|
||||
* <p>The input plain text <code>in</code>, starting at <code>inOff</code>
|
||||
* and ending at <code>(inOff + len - 1)</code>, is encrypted. The result
|
||||
* <p>The input plain text <code>in</code>, starting at <code>inOfs</code>
|
||||
* and ending at <code>(inOfs + len - 1)</code>, is encrypted. The result
|
||||
* is stored in <code>out</code>, starting at <code>outOfs</code>.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
int encrypt(byte[] in, int inOfs, int len, byte[] out, int outOfs) {
|
||||
if ((len % blockSize) != 0) {
|
||||
throw new ProviderException("Internal error in input buffering");
|
||||
}
|
||||
ArrayUtil.blockSizeCheck(len, blockSize);
|
||||
|
||||
checkDataLength(processed, len);
|
||||
|
||||
processAAD();
|
||||
|
||||
if (len > 0) {
|
||||
ArrayUtil.nullAndBoundsCheck(in, inOfs, len);
|
||||
ArrayUtil.nullAndBoundsCheck(out, outOfs, len);
|
||||
|
||||
gctrPAndC.update(in, inOfs, len, out, outOfs);
|
||||
processed += len;
|
||||
ghashAllToS.update(out, outOfs, len);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
@ -451,7 +456,10 @@ final class GaloisCounterMode extends FeedbackCipher {
|
|||
throw new ShortBufferException
|
||||
("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");
|
||||
}
|
||||
|
||||
|
@ -459,6 +467,8 @@ final class GaloisCounterMode extends FeedbackCipher {
|
|||
|
||||
processAAD();
|
||||
if (len > 0) {
|
||||
ArrayUtil.nullAndBoundsCheck(in, inOfs, len);
|
||||
|
||||
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
|
||||
*/
|
||||
int decrypt(byte[] in, int inOfs, int len, byte[] out, int outOfs) {
|
||||
if ((len % blockSize) != 0) {
|
||||
throw new ProviderException("Internal error in input buffering");
|
||||
}
|
||||
ArrayUtil.blockSizeCheck(len, blockSize);
|
||||
|
||||
checkDataLength(ibuffer.size(), len);
|
||||
|
||||
|
@ -504,6 +512,7 @@ final class GaloisCounterMode extends FeedbackCipher {
|
|||
// store internally until decryptFinal is called because
|
||||
// spec mentioned that only return recovered data after tag
|
||||
// is successfully verified
|
||||
ArrayUtil.nullAndBoundsCheck(in, inOfs, len);
|
||||
ibuffer.write(in, inOfs, len);
|
||||
}
|
||||
return 0;
|
||||
|
@ -532,22 +541,28 @@ final class GaloisCounterMode extends FeedbackCipher {
|
|||
if (len < tagLenBytes) {
|
||||
throw new AEADBadTagException("Input too short - need tag");
|
||||
}
|
||||
|
||||
// do this check here can also catch the potential integer overflow
|
||||
// scenario for the subsequent output buffer capacity check.
|
||||
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");
|
||||
}
|
||||
|
||||
processAAD();
|
||||
|
||||
ArrayUtil.nullAndBoundsCheck(in, inOfs, len);
|
||||
|
||||
// get the trailing tag bytes from 'in'
|
||||
byte[] tag = new byte[tagLenBytes];
|
||||
System.arraycopy(in, inOfs + len - tagLenBytes, tag, 0, tagLenBytes);
|
||||
len -= tagLenBytes;
|
||||
|
||||
if (len != 0) {
|
||||
if (len > 0) {
|
||||
ibuffer.write(in, inOfs, len);
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
* 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.ProviderException;
|
||||
import sun.security.util.ArrayUtil;
|
||||
|
||||
/**
|
||||
* 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,
|
||||
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 loopCount = plainLen / numBytes;
|
||||
|
||||
|
@ -189,6 +190,9 @@ final class OutputFeedback extends FeedbackCipher {
|
|||
*/
|
||||
int encryptFinal(byte[] plain, int plainOffset, int plainLen,
|
||||
byte[] cipher, int cipherOffset) {
|
||||
ArrayUtil.nullAndBoundsCheck(plain, plainOffset, plainLen);
|
||||
ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, plainLen);
|
||||
|
||||
int oddBytes = plainLen % numBytes;
|
||||
int len = encrypt(plain, plainOffset, (plainLen - oddBytes),
|
||||
cipher, cipherOffset);
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
* 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.ProviderException;
|
||||
import sun.security.util.ArrayUtil;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -136,9 +137,10 @@ final class PCBC extends FeedbackCipher {
|
|||
int encrypt(byte[] plain, int plainOffset, int plainLen,
|
||||
byte[] cipher, int cipherOffset)
|
||||
{
|
||||
if ((plainLen % blockSize) != 0) {
|
||||
throw new ProviderException("Internal error in input buffering");
|
||||
}
|
||||
ArrayUtil.blockSizeCheck(plainLen, blockSize);
|
||||
ArrayUtil.nullAndBoundsCheck(plain, plainOffset, plainLen);
|
||||
ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, plainLen);
|
||||
|
||||
int i;
|
||||
int endIndex = plainOffset + plainLen;
|
||||
|
||||
|
@ -176,9 +178,10 @@ final class PCBC extends FeedbackCipher {
|
|||
int decrypt(byte[] cipher, int cipherOffset, int cipherLen,
|
||||
byte[] plain, int plainOffset)
|
||||
{
|
||||
if ((cipherLen % blockSize) != 0) {
|
||||
throw new ProviderException("Internal error in input buffering");
|
||||
}
|
||||
ArrayUtil.blockSizeCheck(cipherLen, blockSize);
|
||||
ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, cipherLen);
|
||||
ArrayUtil.nullAndBoundsCheck(plain, plainOffset, cipherLen);
|
||||
|
||||
int i;
|
||||
int endIndex = cipherOffset + cipherLen;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue