mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 14:24:46 +02:00
8209862: CipherCore performance improvement
Co-authored-by: Sergey Kuksenko <sergey.kuksenko@oracle.com> Reviewed-by: apetcher, ascarpino
This commit is contained in:
parent
e898052f3b
commit
497de20391
1 changed files with 126 additions and 86 deletions
|
@ -253,11 +253,10 @@ final class CipherCore {
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the padding mechanism of this cipher.
|
||||
*
|
||||
* @param padding the padding mechanism
|
||||
* @param paddingScheme the padding mechanism
|
||||
*
|
||||
* @exception NoSuchPaddingException if the requested padding mechanism
|
||||
* does not exist
|
||||
|
@ -660,10 +659,7 @@ final class CipherCore {
|
|||
* (e.g., has not been initialized)
|
||||
*/
|
||||
byte[] update(byte[] input, int inputOffset, int inputLen) {
|
||||
if (requireReinit) {
|
||||
throw new IllegalStateException
|
||||
("Must use either different key or iv for GCM encryption");
|
||||
}
|
||||
checkReinit();
|
||||
|
||||
byte[] output = null;
|
||||
try {
|
||||
|
@ -711,10 +707,7 @@ final class CipherCore {
|
|||
*/
|
||||
int update(byte[] input, int inputOffset, int inputLen, byte[] output,
|
||||
int outputOffset) throws ShortBufferException {
|
||||
if (requireReinit) {
|
||||
throw new IllegalStateException
|
||||
("Must use either different key or iv for GCM encryption");
|
||||
}
|
||||
checkReinit();
|
||||
|
||||
// figure out how much can be sent to crypto function
|
||||
int len = Math.addExact(buffered, inputLen);
|
||||
|
@ -849,12 +842,20 @@ final class CipherCore {
|
|||
*/
|
||||
byte[] doFinal(byte[] input, int inputOffset, int inputLen)
|
||||
throws IllegalBlockSizeException, BadPaddingException {
|
||||
byte[] output = null;
|
||||
try {
|
||||
output = new byte[getOutputSizeByOperation(inputLen, true)];
|
||||
int len = doFinal(input, inputOffset, inputLen, output, 0);
|
||||
if (len < output.length) {
|
||||
byte[] copy = Arrays.copyOf(output, len);
|
||||
checkReinit();
|
||||
byte[] output = new byte[getOutputSizeByOperation(inputLen, true)];
|
||||
byte[] finalBuf = prepareInputBuffer(input, inputOffset,
|
||||
inputLen, output, 0);
|
||||
int finalOffset = (finalBuf == input) ? inputOffset : 0;
|
||||
int finalBufLen = (finalBuf == input) ? inputLen : finalBuf.length;
|
||||
|
||||
int outLen = fillOutputBuffer(finalBuf, finalOffset, output, 0,
|
||||
finalBufLen, input);
|
||||
|
||||
endDoFinal();
|
||||
if (outLen < output.length) {
|
||||
byte[] copy = Arrays.copyOf(output, outLen);
|
||||
if (decrypting) {
|
||||
// Zero out internal (ouput) array
|
||||
Arrays.fill(output, (byte) 0x00);
|
||||
|
@ -909,26 +910,81 @@ final class CipherCore {
|
|||
int outputOffset)
|
||||
throws IllegalBlockSizeException, ShortBufferException,
|
||||
BadPaddingException {
|
||||
if (requireReinit) {
|
||||
throw new IllegalStateException
|
||||
("Must use either different key or iv for GCM encryption");
|
||||
}
|
||||
checkReinit();
|
||||
|
||||
int estOutSize = getOutputSizeByOperation(inputLen, true);
|
||||
// check output buffer capacity.
|
||||
// if we are decrypting with padding applied, we can perform this
|
||||
// check only after we have determined how many padding bytes there
|
||||
// are.
|
||||
int outputCapacity = output.length - outputOffset;
|
||||
int minOutSize = (decrypting? (estOutSize - blockSize):estOutSize);
|
||||
if ((output == null) || (outputCapacity < minOutSize)) {
|
||||
throw new ShortBufferException("Output buffer must be "
|
||||
+ "(at least) " + minOutSize + " bytes long");
|
||||
}
|
||||
int outputCapacity = checkOutputCapacity(output, outputOffset,
|
||||
estOutSize);
|
||||
int offset = decrypting ? 0 : outputOffset; // 0 for decrypting
|
||||
byte[] finalBuf = prepareInputBuffer(input, inputOffset,
|
||||
inputLen, output, outputOffset);
|
||||
byte[] outWithPadding = null; // for decrypting only
|
||||
|
||||
int finalOffset = (finalBuf == input) ? inputOffset : 0;
|
||||
int finalBufLen = (finalBuf == input) ? inputLen : finalBuf.length;
|
||||
|
||||
if (decrypting) {
|
||||
// if the size of specified output buffer is less than
|
||||
// the length of the cipher text, then the current
|
||||
// content of cipher has to be preserved in order for
|
||||
// users to retry the call with a larger buffer in the
|
||||
// case of ShortBufferException.
|
||||
if (outputCapacity < estOutSize) {
|
||||
cipher.save();
|
||||
}
|
||||
// create temporary output buffer so that only "real"
|
||||
// data bytes are passed to user's output buffer.
|
||||
outWithPadding = new byte[estOutSize];
|
||||
}
|
||||
byte[] outBuffer = decrypting ? outWithPadding : output;
|
||||
|
||||
int outLen = fillOutputBuffer(finalBuf, finalOffset, outBuffer,
|
||||
offset, finalBufLen, input);
|
||||
|
||||
if (decrypting) {
|
||||
|
||||
if (outputCapacity < outLen) {
|
||||
// restore so users can retry with a larger buffer
|
||||
cipher.restore();
|
||||
throw new ShortBufferException("Output buffer too short: "
|
||||
+ (outputCapacity)
|
||||
+ " bytes given, " + outLen
|
||||
+ " bytes needed");
|
||||
}
|
||||
// copy the result into user-supplied output buffer
|
||||
System.arraycopy(outWithPadding, 0, output, outputOffset, outLen);
|
||||
// decrypt mode. Zero out output data that's not required
|
||||
Arrays.fill(outWithPadding, (byte) 0x00);
|
||||
}
|
||||
endDoFinal();
|
||||
return outLen;
|
||||
}
|
||||
|
||||
private void endDoFinal() {
|
||||
buffered = 0;
|
||||
diffBlocksize = blockSize;
|
||||
if (cipherMode != ECB_MODE) {
|
||||
cipher.reset();
|
||||
}
|
||||
}
|
||||
|
||||
private int unpad(int outLen, byte[] outWithPadding)
|
||||
throws BadPaddingException {
|
||||
int padStart = padding.unpad(outWithPadding, 0, outLen);
|
||||
if (padStart < 0) {
|
||||
throw new BadPaddingException("Given final block not " +
|
||||
"properly padded. Such issues can arise if a bad key " +
|
||||
"is used during decryption.");
|
||||
}
|
||||
outLen = padStart;
|
||||
return outLen;
|
||||
}
|
||||
|
||||
private byte[] prepareInputBuffer(byte[] input, int inputOffset,
|
||||
int inputLen, byte[] output, int outputOffset)
|
||||
throws IllegalBlockSizeException, ShortBufferException {
|
||||
// calculate total input length
|
||||
int len = Math.addExact(buffered, inputLen);
|
||||
|
||||
// calculate padding length
|
||||
int totalLen = Math.addExact(len, cipher.getBufferedLength());
|
||||
int paddingLen = 0;
|
||||
|
@ -958,18 +1014,15 @@ final class CipherCore {
|
|||
* - there are internally buffered bytes
|
||||
* - doing encryption and padding is needed
|
||||
*/
|
||||
byte[] finalBuf = input;
|
||||
int finalOffset = inputOffset;
|
||||
int finalBufLen = inputLen;
|
||||
if ((buffered != 0) || (!decrypting && padding != null) ||
|
||||
((input == output)
|
||||
&& (outputOffset - inputOffset < inputLen)
|
||||
&& (inputOffset - outputOffset < buffer.length))) {
|
||||
byte[] finalBuf;
|
||||
if (decrypting || padding == null) {
|
||||
paddingLen = 0;
|
||||
}
|
||||
finalBuf = new byte[Math.addExact(len, paddingLen)];
|
||||
finalOffset = 0;
|
||||
if (buffered != 0) {
|
||||
System.arraycopy(buffer, 0, finalBuf, 0, buffered);
|
||||
if (!decrypting) {
|
||||
|
@ -980,56 +1033,31 @@ final class CipherCore {
|
|||
}
|
||||
if (inputLen != 0) {
|
||||
System.arraycopy(input, inputOffset, finalBuf,
|
||||
buffered, inputLen);
|
||||
buffered, inputLen);
|
||||
}
|
||||
if (paddingLen != 0) {
|
||||
padding.padWithLen(finalBuf, Math.addExact(buffered, inputLen), paddingLen);
|
||||
}
|
||||
finalBufLen = finalBuf.length;
|
||||
return finalBuf;
|
||||
}
|
||||
int outLen = 0;
|
||||
if (decrypting) {
|
||||
// if the size of specified output buffer is less than
|
||||
// the length of the cipher text, then the current
|
||||
// content of cipher has to be preserved in order for
|
||||
// users to retry the call with a larger buffer in the
|
||||
// case of ShortBufferException.
|
||||
if (outputCapacity < estOutSize) {
|
||||
cipher.save();
|
||||
}
|
||||
// create temporary output buffer so that only "real"
|
||||
// data bytes are passed to user's output buffer.
|
||||
byte[] outWithPadding = new byte[estOutSize];
|
||||
outLen = finalNoPadding(finalBuf, finalOffset, outWithPadding,
|
||||
0, finalBufLen);
|
||||
return input;
|
||||
}
|
||||
|
||||
if (padding != null) {
|
||||
int padStart = padding.unpad(outWithPadding, 0, outLen);
|
||||
if (padStart < 0) {
|
||||
throw new BadPaddingException("Given final block not " +
|
||||
"properly padded. Such issues can arise if a bad key " +
|
||||
"is used during decryption.");
|
||||
}
|
||||
outLen = padStart;
|
||||
private int fillOutputBuffer(byte[] finalBuf, int finalOffset,
|
||||
byte[] output, int outOfs, int finalBufLen,
|
||||
byte[] input)
|
||||
throws ShortBufferException, BadPaddingException,
|
||||
IllegalBlockSizeException {
|
||||
int len;
|
||||
try {
|
||||
len = finalNoPadding(finalBuf, finalOffset, output,
|
||||
outOfs, finalBufLen);
|
||||
if (decrypting && padding != null) {
|
||||
len = unpad(len, output);
|
||||
}
|
||||
|
||||
if (outputCapacity < outLen) {
|
||||
// restore so users can retry with a larger buffer
|
||||
cipher.restore();
|
||||
throw new ShortBufferException("Output buffer too short: "
|
||||
+ (outputCapacity)
|
||||
+ " bytes given, " + outLen
|
||||
+ " bytes needed");
|
||||
}
|
||||
// copy the result into user-supplied output buffer
|
||||
System.arraycopy(outWithPadding, 0, output, outputOffset, outLen);
|
||||
// decrypt mode. Zero out output data that's not required
|
||||
Arrays.fill(outWithPadding, (byte) 0x00);
|
||||
} else { // encrypting
|
||||
try {
|
||||
outLen = finalNoPadding(finalBuf, finalOffset, output,
|
||||
outputOffset, finalBufLen);
|
||||
} finally {
|
||||
return len;
|
||||
} finally {
|
||||
if (!decrypting) {
|
||||
// reset after doFinal() for GCM encryption
|
||||
requireReinit = (cipherMode == GCM_MODE);
|
||||
if (finalBuf != input) {
|
||||
|
@ -1038,13 +1066,28 @@ final class CipherCore {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buffered = 0;
|
||||
diffBlocksize = blockSize;
|
||||
if (cipherMode != ECB_MODE) {
|
||||
cipher.reset();
|
||||
private int checkOutputCapacity(byte[] output, int outputOffset,
|
||||
int estOutSize) throws ShortBufferException {
|
||||
// check output buffer capacity.
|
||||
// if we are decrypting with padding applied, we can perform this
|
||||
// check only after we have determined how many padding bytes there
|
||||
// are.
|
||||
int outputCapacity = output.length - outputOffset;
|
||||
int minOutSize = decrypting ? (estOutSize - blockSize) : estOutSize;
|
||||
if ((output == null) || (outputCapacity < minOutSize)) {
|
||||
throw new ShortBufferException("Output buffer must be "
|
||||
+ "(at least) " + minOutSize + " bytes long");
|
||||
}
|
||||
return outputCapacity;
|
||||
}
|
||||
|
||||
private void checkReinit() {
|
||||
if (requireReinit) {
|
||||
throw new IllegalStateException
|
||||
("Must use either different key or iv for GCM encryption");
|
||||
}
|
||||
return outLen;
|
||||
}
|
||||
|
||||
private int finalNoPadding(byte[] in, int inOfs, byte[] out, int outOfs,
|
||||
|
@ -1177,10 +1220,7 @@ final class CipherCore {
|
|||
* @since 1.8
|
||||
*/
|
||||
void updateAAD(byte[] src, int offset, int len) {
|
||||
if (requireReinit) {
|
||||
throw new IllegalStateException
|
||||
("Must use either different key or iv for GCM encryption");
|
||||
}
|
||||
checkReinit();
|
||||
cipher.updateAAD(src, offset, len);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue