Skip to content

Commit

Permalink
Reset inputIsEmpty in engineInit
Browse files Browse the repository at this point in the history
+ Test cases are added to ensure that inputIsEmpty is reset.
  • Loading branch information
amirhosv committed May 15, 2024
1 parent 9926855 commit 021bfdf
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 2 deletions.
9 changes: 7 additions & 2 deletions src/com/amazon/corretto/crypto/provider/AesCbcSpi.java
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ protected void engineInit(
this.iv = iv;
this.key = keyBytes;
this.unprocessedInput = 0;
this.inputIsEmpty = true;
initLastBlock();
}

Expand Down Expand Up @@ -377,7 +378,9 @@ private int update(
final byte[] outputArray,
final int outputOffset) {

inputIsEmpty = inputIsEmpty && (inputLen == 0);
if (inputLen > 0) {
inputIsEmpty = false;
}

// Unlike, doFinal (which needs to decide if a context should be released or not), update always
// has to save the context.
Expand Down Expand Up @@ -549,7 +552,9 @@ private int doFinal(
final byte[] outputArray,
final int outputOffset) {

inputIsEmpty = inputIsEmpty && (inputLen == 0);
if (inputLen > 0) {
inputIsEmpty = false;
}

if (inputIsEmpty && (opMode == DEC_MODE) && (!noPadding())) {
// AWS-LC's behavior in treating empty input when decrypting with padding differs from SunJCE.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,39 @@ public void emptyCipherTextWithPaddingEnabledShouldProduceEmptyPlaintext() throw
assertEquals(16, sun.doFinal().length);
}

@Test
public void ensureInputEmptyIsResetAfterAnOperation() throws Exception {
final SecretKeySpec key = genAesKey(10, 128);
final IvParameterSpec iv = genIv(10, 16);
final Cipher accp = accpCipher();

accp.init(Cipher.ENCRYPT_MODE, key, iv);

// First we encrypt with a non-empty input.
assertEquals(16, accp.doFinal(genData(10, 10)).length);
// Now we decrypt with the same cipher object and empty input:
accp.init(Cipher.DECRYPT_MODE, key, iv);
assertEquals(0, accp.doFinal().length);
}

@Test
public void ensureInputEmptyIsResetAfterAnOperationWithBadPaddingToo() throws Exception {
final SecretKeySpec key = genAesKey(10, 128);
final IvParameterSpec iv = genIv(10, 16);
final Cipher accp = accpCipher();

accp.init(Cipher.DECRYPT_MODE, key, iv);
accp.update(new byte[8]);
// inputIsEmpty is false. We pass bad cipher text to cause bad padding.
assertThrows(BadPaddingException.class, () -> accp.doFinal(new byte[8]));
// The cipher must need re-initialization.
assertThrows(IllegalStateException.class, () -> accp.doFinal());
// After initialization, inputIsEmpty should be rest to true and produce zero output when
// decrypting empty input.
accp.init(Cipher.DECRYPT_MODE, key, iv);
assertEquals(0, accp.doFinal().length);
}

@ParameterizedTest
@MethodSource("arrayTestParams")
public void testArrayOneShot(final long seed, final int keySize) throws Exception {
Expand Down
33 changes: 33 additions & 0 deletions tst/com/amazon/corretto/crypto/provider/test/AesCbcTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,39 @@ public void emptyCipherTextWithPaddingEnabledShouldProduceEmptyPlaintext() throw
assertArrayEquals(sun.doFinal(), accpCipherText);
}

@Test
public void ensureInputEmptyIsResetAfterAnOperation() throws Exception {
final SecretKeySpec key = genAesKey(10, 128);
final IvParameterSpec iv = genIv(10, 16);
final Cipher accp = accpAesCbcCipher(true);

accp.init(Cipher.ENCRYPT_MODE, key, iv);

// First we encrypt with a non-empty input.
assertEquals(16, accp.doFinal(genData(10, 10)).length);
// Now we decrypt with the same cipher object and empty input:
accp.init(Cipher.DECRYPT_MODE, key, iv);
assertEquals(0, accp.doFinal().length);
}

@Test
public void ensureInputEmptyIsResetAfterAnOperationWithBadPaddingToo() throws Exception {
final SecretKeySpec key = genAesKey(10, 128);
final IvParameterSpec iv = genIv(10, 16);
final Cipher accp = accpAesCbcCipher(true);

accp.init(Cipher.DECRYPT_MODE, key, iv);
accp.update(new byte[8]);
// inputIsEmpty is false. We pass bad cipher text to cause bad padding.
assertThrows(BadPaddingException.class, () -> accp.doFinal(new byte[8]));
// The cipher must need re-initialization.
assertThrows(IllegalStateException.class, () -> accp.doFinal());
// After initialization, inputIsEmpty should be rest to true and produce zero output when
// decrypting empty input.
accp.init(Cipher.DECRYPT_MODE, key, iv);
assertEquals(0, accp.doFinal().length);
}

@Test
public void testPkcs7Name() throws Exception {
// SunJCE does not recognize AES/CBC/PKCS7Padding, but BouncyCastle does:
Expand Down

0 comments on commit 021bfdf

Please sign in to comment.