mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 14:24:46 +02:00
8224997: ChaCha20-Poly1305 TLS cipher suite decryption throws ShortBufferException
Reviewed-by: xuelei
This commit is contained in:
parent
07c1c7fcd8
commit
742e9f26c8
2 changed files with 228 additions and 26 deletions
|
@ -33,12 +33,11 @@ import java.nio.ByteBuffer;
|
|||
import java.nio.ByteOrder;
|
||||
import java.security.*;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import javax.crypto.*;
|
||||
import javax.crypto.spec.ChaCha20ParameterSpec;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.crypto.*;
|
||||
import sun.security.util.DerValue;
|
||||
|
||||
/**
|
||||
|
@ -134,8 +133,7 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
protected ChaCha20Cipher() {
|
||||
}
|
||||
protected ChaCha20Cipher() { }
|
||||
|
||||
/**
|
||||
* Set the mode of operation. Since this is a stream cipher, there
|
||||
|
@ -185,11 +183,13 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the output size based on an input length. In simple stream-cipher
|
||||
* Get the output size required to hold the result of the next update or
|
||||
* doFinal operation. In simple stream-cipher
|
||||
* mode, the output size will equal the input size. For ChaCha20-Poly1305
|
||||
* for encryption the output size will be the sum of the input length
|
||||
* and tag length. For decryption, the output size will be the input
|
||||
* length less the tag length or zero, whichever is larger.
|
||||
* and tag length. For decryption, the output size will be the input
|
||||
* length plus any previously unprocessed data minus the tag
|
||||
* length, minimum zero.
|
||||
*
|
||||
* @param inputLen the length in bytes of the input
|
||||
*
|
||||
|
@ -197,17 +197,7 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||
*/
|
||||
@Override
|
||||
protected int engineGetOutputSize(int inputLen) {
|
||||
int outLen = 0;
|
||||
|
||||
if (mode == MODE_NONE) {
|
||||
outLen = inputLen;
|
||||
} else if (mode == MODE_AEAD) {
|
||||
outLen = (direction == Cipher.ENCRYPT_MODE) ?
|
||||
Math.addExact(inputLen, TAG_LENGTH) :
|
||||
Integer.max(inputLen - TAG_LENGTH, 0);
|
||||
}
|
||||
|
||||
return outLen;
|
||||
return engine.getOutputSize(inputLen, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -237,13 +227,10 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||
AlgorithmParameters params = null;
|
||||
if (mode == MODE_AEAD) {
|
||||
try {
|
||||
// Force the 12-byte nonce into a DER-encoded OCTET_STRING
|
||||
byte[] derNonce = new byte[nonce.length + 2];
|
||||
derNonce[0] = 0x04; // OCTET_STRING tag
|
||||
derNonce[1] = (byte)nonce.length; // 12-byte length;
|
||||
System.arraycopy(nonce, 0, derNonce, 2, nonce.length);
|
||||
// Place the 12-byte nonce into a DER-encoded OCTET_STRING
|
||||
params = AlgorithmParameters.getInstance("ChaCha20-Poly1305");
|
||||
params.init(derNonce);
|
||||
params.init((new DerValue(
|
||||
DerValue.tag_OctetString, nonce).toByteArray()));
|
||||
} catch (NoSuchAlgorithmException | IOException exc) {
|
||||
throw new RuntimeException(exc);
|
||||
}
|
||||
|
@ -638,7 +625,7 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||
*/
|
||||
@Override
|
||||
protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {
|
||||
byte[] out = new byte[inLen];
|
||||
byte[] out = new byte[engine.getOutputSize(inLen, false)];
|
||||
try {
|
||||
engine.doUpdate(in, inOfs, inLen, out, 0);
|
||||
} catch (ShortBufferException | KeyException exc) {
|
||||
|
@ -696,7 +683,7 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||
@Override
|
||||
protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)
|
||||
throws AEADBadTagException {
|
||||
byte[] output = new byte[engineGetOutputSize(inLen)];
|
||||
byte[] output = new byte[engine.getOutputSize(inLen, true)];
|
||||
try {
|
||||
engine.doFinal(in, inOfs, inLen, output, 0);
|
||||
} catch (ShortBufferException | KeyException exc) {
|
||||
|
@ -1157,6 +1144,17 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||
* Interface for the underlying processing engines for ChaCha20
|
||||
*/
|
||||
interface ChaChaEngine {
|
||||
/**
|
||||
* Size an output buffer based on the input and where applicable
|
||||
* the current state of the engine in a multipart operation.
|
||||
*
|
||||
* @param inLength the input length.
|
||||
* @param isFinal true if this is invoked from a doFinal call.
|
||||
*
|
||||
* @return the recommended size for the output buffer.
|
||||
*/
|
||||
int getOutputSize(int inLength, boolean isFinal);
|
||||
|
||||
/**
|
||||
* Perform a multi-part update for ChaCha20.
|
||||
*
|
||||
|
@ -1200,6 +1198,12 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||
|
||||
private EngineStreamOnly () { }
|
||||
|
||||
@Override
|
||||
public int getOutputSize(int inLength, boolean isFinal) {
|
||||
// The isFinal parameter is not relevant in this kind of engine
|
||||
return inLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int doUpdate(byte[] in, int inOff, int inLen, byte[] out,
|
||||
int outOff) throws ShortBufferException, KeyException {
|
||||
|
@ -1234,6 +1238,11 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||
|
||||
private final class EngineAEADEnc implements ChaChaEngine {
|
||||
|
||||
@Override
|
||||
public int getOutputSize(int inLength, boolean isFinal) {
|
||||
return (isFinal ? Math.addExact(inLength, TAG_LENGTH) : inLength);
|
||||
}
|
||||
|
||||
private EngineAEADEnc() throws InvalidKeyException {
|
||||
initAuthenticator();
|
||||
counter = 1;
|
||||
|
@ -1294,6 +1303,18 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||
private final ByteArrayOutputStream cipherBuf;
|
||||
private final byte[] tag;
|
||||
|
||||
@Override
|
||||
public int getOutputSize(int inLen, boolean isFinal) {
|
||||
// If we are performing a decrypt-update we should always return
|
||||
// zero length since we cannot return any data until the tag has
|
||||
// been consumed and verified. CipherSpi.engineGetOutputSize will
|
||||
// always set isFinal to true to get the required output buffer
|
||||
// size.
|
||||
return (isFinal ?
|
||||
Integer.max(Math.addExact((inLen - TAG_LENGTH),
|
||||
cipherBuf.size()), 0) : 0);
|
||||
}
|
||||
|
||||
private EngineAEADDec() throws InvalidKeyException {
|
||||
initAuthenticator();
|
||||
counter = 1;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue