提交 f1bd41ca 编写于 作者: C coffeys

8209862: CipherCore performance improvement

Reviewed-by: apetcher, ascarpino
Contributed-by: sergey.kuksenko@oracle.com, sean.coffey@oracle.com
上级 1d3c26d0
...@@ -253,11 +253,10 @@ final class CipherCore { ...@@ -253,11 +253,10 @@ final class CipherCore {
return result; return result;
} }
/** /**
* Sets the padding mechanism of this cipher. * Sets the padding mechanism of this cipher.
* *
* @param padding the padding mechanism * @param paddingScheme the padding mechanism
* *
* @exception NoSuchPaddingException if the requested padding mechanism * @exception NoSuchPaddingException if the requested padding mechanism
* does not exist * does not exist
...@@ -660,10 +659,7 @@ final class CipherCore { ...@@ -660,10 +659,7 @@ final class CipherCore {
* (e.g., has not been initialized) * (e.g., has not been initialized)
*/ */
byte[] update(byte[] input, int inputOffset, int inputLen) { byte[] update(byte[] input, int inputOffset, int inputLen) {
if (requireReinit) { checkReinit();
throw new IllegalStateException
("Must use either different key or iv for GCM encryption");
}
byte[] output = null; byte[] output = null;
try { try {
...@@ -711,10 +707,7 @@ final class CipherCore { ...@@ -711,10 +707,7 @@ final class CipherCore {
*/ */
int update(byte[] input, int inputOffset, int inputLen, byte[] output, int update(byte[] input, int inputOffset, int inputLen, byte[] output,
int outputOffset) throws ShortBufferException { int outputOffset) throws ShortBufferException {
if (requireReinit) { checkReinit();
throw new IllegalStateException
("Must use either different key or iv for GCM encryption");
}
// figure out how much can be sent to crypto function // figure out how much can be sent to crypto function
int len = Math.addExact(buffered, inputLen); int len = Math.addExact(buffered, inputLen);
...@@ -849,12 +842,20 @@ final class CipherCore { ...@@ -849,12 +842,20 @@ final class CipherCore {
*/ */
byte[] doFinal(byte[] input, int inputOffset, int inputLen) byte[] doFinal(byte[] input, int inputOffset, int inputLen)
throws IllegalBlockSizeException, BadPaddingException { throws IllegalBlockSizeException, BadPaddingException {
byte[] output = null;
try { try {
output = new byte[getOutputSizeByOperation(inputLen, true)]; checkReinit();
int len = doFinal(input, inputOffset, inputLen, output, 0); byte[] output = new byte[getOutputSizeByOperation(inputLen, true)];
if (len < output.length) { byte[] finalBuf = prepareInputBuffer(input, inputOffset,
byte[] copy = Arrays.copyOf(output, len); 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) { if (decrypting) {
// Zero out internal (ouput) array // Zero out internal (ouput) array
Arrays.fill(output, (byte) 0x00); Arrays.fill(output, (byte) 0x00);
...@@ -909,26 +910,81 @@ final class CipherCore { ...@@ -909,26 +910,81 @@ final class CipherCore {
int outputOffset) int outputOffset)
throws IllegalBlockSizeException, ShortBufferException, throws IllegalBlockSizeException, ShortBufferException,
BadPaddingException { BadPaddingException {
if (requireReinit) { checkReinit();
throw new IllegalStateException
("Must use either different key or iv for GCM encryption");
}
int estOutSize = getOutputSizeByOperation(inputLen, true); int estOutSize = getOutputSizeByOperation(inputLen, true);
// check output buffer capacity. int outputCapacity = checkOutputCapacity(output, outputOffset,
// if we are decrypting with padding applied, we can perform this estOutSize);
// check only after we have determined how many padding bytes there int offset = decrypting ? 0 : outputOffset; // 0 for decrypting
// are. byte[] finalBuf = prepareInputBuffer(input, inputOffset,
int outputCapacity = output.length - outputOffset; inputLen, output, outputOffset);
int minOutSize = (decrypting? (estOutSize - blockSize):estOutSize); byte[] outWithPadding = null; // for decrypting only
if ((output == null) || (outputCapacity < minOutSize)) {
throw new ShortBufferException("Output buffer must be " int finalOffset = (finalBuf == input) ? inputOffset : 0;
+ "(at least) " + minOutSize + " bytes long"); 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 // calculate total input length
int len = Math.addExact(buffered, inputLen); int len = Math.addExact(buffered, inputLen);
// calculate padding length // calculate padding length
int totalLen = Math.addExact(len, cipher.getBufferedLength()); int totalLen = Math.addExact(len, cipher.getBufferedLength());
int paddingLen = 0; int paddingLen = 0;
...@@ -958,18 +1014,15 @@ final class CipherCore { ...@@ -958,18 +1014,15 @@ final class CipherCore {
* - there are internally buffered bytes * - there are internally buffered bytes
* - doing encryption and padding is needed * - doing encryption and padding is needed
*/ */
byte[] finalBuf = input;
int finalOffset = inputOffset;
int finalBufLen = inputLen;
if ((buffered != 0) || (!decrypting && padding != null) || if ((buffered != 0) || (!decrypting && padding != null) ||
((input == output) ((input == output)
&& (outputOffset - inputOffset < inputLen) && (outputOffset - inputOffset < inputLen)
&& (inputOffset - outputOffset < buffer.length))) { && (inputOffset - outputOffset < buffer.length))) {
byte[] finalBuf;
if (decrypting || padding == null) { if (decrypting || padding == null) {
paddingLen = 0; paddingLen = 0;
} }
finalBuf = new byte[Math.addExact(len, paddingLen)]; finalBuf = new byte[Math.addExact(len, paddingLen)];
finalOffset = 0;
if (buffered != 0) { if (buffered != 0) {
System.arraycopy(buffer, 0, finalBuf, 0, buffered); System.arraycopy(buffer, 0, finalBuf, 0, buffered);
if (!decrypting) { if (!decrypting) {
...@@ -985,51 +1038,26 @@ final class CipherCore { ...@@ -985,51 +1038,26 @@ final class CipherCore {
if (paddingLen != 0) { if (paddingLen != 0) {
padding.padWithLen(finalBuf, Math.addExact(buffered, inputLen), paddingLen); padding.padWithLen(finalBuf, Math.addExact(buffered, inputLen), paddingLen);
} }
finalBufLen = finalBuf.length; return finalBuf;
} }
int outLen = 0; return input;
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);
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;
} }
if (outputCapacity < outLen) { private int fillOutputBuffer(byte[] finalBuf, int finalOffset,
// restore so users can retry with a larger buffer byte[] output, int outOfs, int finalBufLen,
cipher.restore(); byte[] input)
throw new ShortBufferException("Output buffer too short: " throws ShortBufferException, BadPaddingException,
+ (outputCapacity) IllegalBlockSizeException {
+ " bytes given, " + outLen int len;
+ " 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 { try {
outLen = finalNoPadding(finalBuf, finalOffset, output, len = finalNoPadding(finalBuf, finalOffset, output,
outputOffset, finalBufLen); outOfs, finalBufLen);
if (decrypting && padding != null) {
len = unpad(len, output);
}
return len;
} finally { } finally {
if (!decrypting) {
// reset after doFinal() for GCM encryption // reset after doFinal() for GCM encryption
requireReinit = (cipherMode == GCM_MODE); requireReinit = (cipherMode == GCM_MODE);
if (finalBuf != input) { if (finalBuf != input) {
...@@ -1038,13 +1066,28 @@ final class CipherCore { ...@@ -1038,13 +1066,28 @@ final class CipherCore {
} }
} }
} }
}
buffered = 0; private int checkOutputCapacity(byte[] output, int outputOffset,
diffBlocksize = blockSize; int estOutSize) throws ShortBufferException {
if (cipherMode != ECB_MODE) { // check output buffer capacity.
cipher.reset(); // 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, private int finalNoPadding(byte[] in, int inOfs, byte[] out, int outOfs,
...@@ -1177,10 +1220,7 @@ final class CipherCore { ...@@ -1177,10 +1220,7 @@ final class CipherCore {
* @since 1.8 * @since 1.8
*/ */
void updateAAD(byte[] src, int offset, int len) { void updateAAD(byte[] src, int offset, int len) {
if (requireReinit) { checkReinit();
throw new IllegalStateException
("Must use either different key or iv for GCM encryption");
}
cipher.updateAAD(src, offset, len); cipher.updateAAD(src, offset, len);
} }
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册