From 921a3e48dee400213a655ea9c6ae6802bd68c10c Mon Sep 17 00:00:00 2001 From: Kostas Tsiounis Date: Tue, 27 Jun 2023 15:20:32 -0400 Subject: [PATCH] Improve speed of cipher operations for large inputs and allow unpadding at offset of output --- .../com/sun/crypto/provider/CipherCore.java | 69 ++++++++++++++----- 1 file changed, 50 insertions(+), 19 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java b/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java index 80742815ca..7b9ac14fce 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java @@ -897,12 +897,26 @@ byte[] doFinal(byte[] input, int inputOffset, int inputLen) try { checkReinit(); byte[] output = new byte[getOutputSizeByOperation(inputLen, true)]; - byte[] finalBuf = prepareInputBuffer(input, inputOffset, - inputLen, output, 0); + int outputOffset = 0; + int outLen = 0; + + if (inputLen > 0) { + /* + * Call the update() method to get rid of as many bytes as + * possible before potentially copying array. + */ + int updateOutLen = update(input, inputOffset, inputLen, output, outputOffset); + inputOffset = inputLen; + inputLen = 0; + outputOffset += updateOutLen; + outLen = updateOutLen; + } + + byte[] finalBuf = prepareInputBuffer(input, inputOffset, inputLen, output, outputOffset); int finalOffset = (finalBuf == input) ? inputOffset : 0; int finalBufLen = (finalBuf == input) ? inputLen : finalBuf.length; - int outLen = fillOutputBuffer(finalBuf, finalOffset, output, 0, + outLen += fillOutputBuffer(finalBuf, finalOffset, output, outputOffset, finalBufLen, input); endDoFinal(); @@ -967,13 +981,6 @@ int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int estOutSize = getOutputSizeByOperation(inputLen, true); int outputCapacity = checkOutputCapacity(output, outputOffset, estOutSize); - int offset = outputOffset; // 0 for decrypting - byte[] finalBuf = prepareInputBuffer(input, inputOffset, - inputLen, output, outputOffset); - byte[] internalOutput = 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 @@ -984,18 +991,43 @@ int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output, if (outputCapacity < estOutSize) { cipher.save(); } + } + + int outLen = 0; + int estFinalBuffSize = estOutSize; + if (inputLen > 0) { + /* + * Call the update() method to get rid of as many bytes as + * possible before potentially copying array. + */ + int updateOutLen = update(input, inputOffset, inputLen, output, outputOffset); + inputOffset = inputLen; + inputLen = 0; + outputOffset += updateOutLen; + outLen += updateOutLen; + estFinalBuffSize -= updateOutLen; + } + + int offset = outputOffset; + byte[] finalBuf = prepareInputBuffer(input, inputOffset, inputLen, output, outputOffset); + byte[] internalOutput = null; // for decrypting only + + int finalOffset = (finalBuf == input) ? inputOffset : 0; + int finalBufLen = (finalBuf == input) ? inputLen : finalBuf.length; + + if (decrypting) { if (outputCapacity < estOutSize || padding != null) { // create temporary output buffer if the estimated size is larger // than the user-provided buffer or a padding needs to be removed // before copying the unpadded result to the output buffer - internalOutput = new byte[estOutSize]; + internalOutput = new byte[estFinalBuffSize]; offset = 0; } } byte[] outBuffer = (internalOutput != null) ? internalOutput : output; - - int outLen = fillOutputBuffer(finalBuf, finalOffset, outBuffer, + int outBuffLen = fillOutputBuffer(finalBuf, finalOffset, outBuffer, offset, finalBufLen, input); + outLen += outBuffLen; if (decrypting) { @@ -1009,7 +1041,7 @@ int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output, } // copy the result into user-supplied output buffer if (internalOutput != null) { - System.arraycopy(internalOutput, 0, output, outputOffset, outLen); + System.arraycopy(internalOutput, 0, output, outputOffset, outBuffLen); // decrypt mode. Zero out output data that's not required Arrays.fill(internalOutput, (byte) 0x00); } @@ -1026,16 +1058,15 @@ private void endDoFinal() { } } - private int unpad(int outLen, byte[] outWithPadding) + private int unpad(int outLen, int off, byte[] outWithPadding) throws BadPaddingException { - int padStart = padding.unpad(outWithPadding, 0, outLen); + int padStart = padding.unpad(outWithPadding, off, 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; + return padStart - off; } private byte[] prepareInputBuffer(byte[] input, int inputOffset, @@ -1111,7 +1142,7 @@ private int fillOutputBuffer(byte[] finalBuf, int finalOffset, len = finalNoPadding(finalBuf, finalOffset, output, outOfs, finalBufLen); if (decrypting && padding != null) { - len = unpad(len, output); + len = unpad(len, outOfs, output); } return len; } finally {