diff --git a/src/main/java/com/wolfssl/provider/jce/WolfCryptCipher.java b/src/main/java/com/wolfssl/provider/jce/WolfCryptCipher.java index dc830ca..e24d47b 100644 --- a/src/main/java/com/wolfssl/provider/jce/WolfCryptCipher.java +++ b/src/main/java/com/wolfssl/provider/jce/WolfCryptCipher.java @@ -303,12 +303,19 @@ public class WolfCryptCipher extends CipherSpi { if (paddingType == PaddingType.WC_NONE) { if (cipherMode == CipherMode.WC_GCM) { /* In AES-GCM mode we append the authentication tag - * to the end of ciphertext */ - size = inputLen + this.gcmTagLen; + * to the end of ciphertext, When decrypting, output + * size will have it taken off. */ + if (this.direction == OpMode.WC_ENCRYPT) { + size = inputLen + this.gcmTagLen; + } + else { + size = inputLen - this.gcmTagLen; + } + size = Math.max(size, 0); } else { - /* wolfCrypt expects input to be padded by application to - * block size, thus output is same size as input */ + /* wolfCrypt expects input to be padded by application + * to block size, thus output is same size as input */ size = inputLen; } } diff --git a/src/test/java/com/wolfssl/provider/jce/test/WolfCryptCipherTest.java b/src/test/java/com/wolfssl/provider/jce/test/WolfCryptCipherTest.java index e7ad1c5..b13bede 100644 --- a/src/test/java/com/wolfssl/provider/jce/test/WolfCryptCipherTest.java +++ b/src/test/java/com/wolfssl/provider/jce/test/WolfCryptCipherTest.java @@ -2250,6 +2250,66 @@ public class WolfCryptCipherTest { } } + /** + * Test Cipher("AES/GCM/NoPadding") getOutputSize() method for various + * use cases. + */ + @Test + public void testAesGcmGetOutputSize() throws Exception { + + final int TAG_LENGTH_BYTES = 16; /* Default tag length */ + final int KEY_LENGTH_BYTES = 16; /* 128-bit AES key */ + final int IV_LENGTH_BYTES = 12; + + /* Fill key and IV with non-zero values */ + byte[] keyBytes = new byte[KEY_LENGTH_BYTES]; + java.util.Arrays.fill(keyBytes, (byte) 0x01); + SecretKeySpec key = new SecretKeySpec(keyBytes, "AES"); + + byte[] iv = new byte[IV_LENGTH_BYTES]; + java.util.Arrays.fill(iv, (byte) 0x02); + GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BYTES * 8, iv); + + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", jceProvider); + + /* Test ENCRYPT with zero-length input */ + cipher.init(Cipher.ENCRYPT_MODE, key, spec); + assertEquals("Output size for zero-length input should be tag length", + TAG_LENGTH_BYTES, cipher.getOutputSize(0)); + + /* Test ENCRYPT with small input, re-init to reset state */ + cipher.init(Cipher.ENCRYPT_MODE, key, spec); + assertEquals("Output size should be input length plus tag length", + 10 + TAG_LENGTH_BYTES, cipher.getOutputSize(10)); + + /* Test ENCRYPT with block boundary input */ + cipher.init(Cipher.ENCRYPT_MODE, key, spec); + assertEquals("Output size should be input length plus tag length " + + "at block boundary", 16 + TAG_LENGTH_BYTES, + cipher.getOutputSize(16)); + + /* Test DECRYPT with tag included */ + cipher.init(Cipher.DECRYPT_MODE, key, spec); + assertEquals("Output size for decryption should be input length " + + "minus tag length", 10, cipher.getOutputSize(10 + TAG_LENGTH_BYTES)); + + /* Test ENCRYPT after partial update */ + byte[] partialInput = new byte[5]; + cipher.init(Cipher.ENCRYPT_MODE, key, spec); + cipher.update(partialInput); /* Process some data */ + assertEquals("Output size after update should account for remaining " + + "input plus tag", 10 + TAG_LENGTH_BYTES, cipher.getOutputSize(10)); + + /* Test getOutputSize() before initialization, expect exception */ + Cipher uninitializedCipher = Cipher.getInstance("AES/GCM/NoPadding"); + try { + uninitializedCipher.getOutputSize(10); + fail("Expected IllegalStateException for uninitialized cipher"); + } catch (IllegalStateException e) { + /* Expected exception */ + } + } + @Test public void testDESedeCbcNoPadding() throws NoSuchProviderException, NoSuchAlgorithmException,