diff --git a/src/share/classes/com/sun/crypto/provider/CipherCore.java b/src/share/classes/com/sun/crypto/provider/CipherCore.java index 81027aab8dc0a7720ffee0c5d6d60971046a8f38..f641eaa320fc7ee76adbafc45d111ee14b3f099b 100644 --- a/src/share/classes/com/sun/crypto/provider/CipherCore.java +++ b/src/share/classes/com/sun/crypto/provider/CipherCore.java @@ -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); - - 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; - } + return input; + } - 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"); + 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); } - // 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); } }