-
Bug
-
Resolution: Fixed
-
P4
-
22
-
b25
Cipher class enforces some restrictions on AEAD use:
- ChaCha20 cipher is preventing the counter from wrapping around
- AEAD decryption does not return any data from Cipher.update. Decrypted data is only returned from doFinal after verifying the tag. DoFinal can not produce more than 2GB of data, so decrypting longer buffers is impossible.
We should document the exception types thrown in response to these error conditions. Currently the exception types thrown are not documented, and are inconsistent across ciphers.
I did an experiment to verify what happens if I encrypt/decrypt larger amounts of data, see attached reproducer. Results:
ChaCha20-Poly1305, encryption fails after 256GB with:
java.lang.RuntimeException: java.security.KeyException: Counter exhausted. Reinitialize with new key and/or nonce
at java.base/com.sun.crypto.provider.ChaCha20Cipher.engineUpdate(ChaCha20Cipher.java:653)
at java.base/javax.crypto.Cipher.update(Cipher.java:1869)
at com.test.AEADWrap.crypt(AEADWrap.java:57)
at com.test.AEADWrap.main(AEADWrap.java:40)
Caused by: java.security.KeyException: Counter exhausted. Reinitialize with new key and/or nonce
at java.base/com.sun.crypto.provider.ChaCha20Cipher.chaCha20Transform(ChaCha20Cipher.java:1046)
at java.base/com.sun.crypto.provider.ChaCha20Cipher$EngineAEADEnc.doUpdate(ChaCha20Cipher.java:1326)
at java.base/com.sun.crypto.provider.ChaCha20Cipher.engineUpdate(ChaCha20Cipher.java:651)
... 3 more
ChaCha20-Poly1305, decryption fails after 2GB with:
java.lang.OutOfMemoryError: Required array length 1073741840 + 1073741840 is too large
at java.base/jdk.internal.util.ArraysSupport.hugeLength(ArraysSupport.java:752)
at java.base/jdk.internal.util.ArraysSupport.newLength(ArraysSupport.java:745)
at java.base/java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:100)
at java.base/java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:132)
at java.base/com.sun.crypto.provider.ChaCha20Cipher$EngineAEADDec.doUpdate(ChaCha20Cipher.java:1392)
at java.base/com.sun.crypto.provider.ChaCha20Cipher.engineUpdate(ChaCha20Cipher.java:651)
at java.base/javax.crypto.Cipher.update(Cipher.java:1869)
at com.test.AEADWrap.crypt(AEADWrap.java:57)
at com.test.AEADWrap.main(AEADWrap.java:46)
AES-GCM encryption fails after 2GB with:
java.security.ProviderException: SunJCE provider only supports input size up to 2147483647 bytes
at java.base/com.sun.crypto.provider.GaloisCounterMode$GCMEncrypt.checkDataLength(GaloisCounterMode.java:1098)
at java.base/com.sun.crypto.provider.GaloisCounterMode$GCMEncrypt.doUpdate(GaloisCounterMode.java:1143)
at java.base/com.sun.crypto.provider.GaloisCounterMode$GCMEncrypt.doUpdate(GaloisCounterMode.java:1120)
at java.base/com.sun.crypto.provider.GaloisCounterMode.engineUpdate(GaloisCounterMode.java:349)
at java.base/javax.crypto.Cipher.update(Cipher.java:1869)
at com.test.AEADWrap.crypt(AEADWrap.java:57)
at com.test.AEADWrap.main(AEADWrap.java:25)
AES-GCM decryption fails after 2GB with:
java.lang.OutOfMemoryError: Required array length 1073741840 + 1073741840 is too large
at java.base/jdk.internal.util.ArraysSupport.hugeLength(ArraysSupport.java:752)
at java.base/jdk.internal.util.ArraysSupport.newLength(ArraysSupport.java:745)
at java.base/java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:100)
at java.base/java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:132)
at java.base/com.sun.crypto.provider.GaloisCounterMode$GCMDecrypt.doUpdate(GaloisCounterMode.java:1458)
at java.base/com.sun.crypto.provider.GaloisCounterMode$GCMDecrypt.doUpdate(GaloisCounterMode.java:1441)
at java.base/com.sun.crypto.provider.GaloisCounterMode.engineUpdate(GaloisCounterMode.java:349)
at java.base/javax.crypto.Cipher.update(Cipher.java:1869)
at com.test.AEADWrap.crypt(AEADWrap.java:57)
at com.test.AEADWrap.main(AEADWrap.java:31)
- ChaCha20 cipher is preventing the counter from wrapping around
- AEAD decryption does not return any data from Cipher.update. Decrypted data is only returned from doFinal after verifying the tag. DoFinal can not produce more than 2GB of data, so decrypting longer buffers is impossible.
We should document the exception types thrown in response to these error conditions. Currently the exception types thrown are not documented, and are inconsistent across ciphers.
I did an experiment to verify what happens if I encrypt/decrypt larger amounts of data, see attached reproducer. Results:
ChaCha20-Poly1305, encryption fails after 256GB with:
java.lang.RuntimeException: java.security.KeyException: Counter exhausted. Reinitialize with new key and/or nonce
at java.base/com.sun.crypto.provider.ChaCha20Cipher.engineUpdate(ChaCha20Cipher.java:653)
at java.base/javax.crypto.Cipher.update(Cipher.java:1869)
at com.test.AEADWrap.crypt(AEADWrap.java:57)
at com.test.AEADWrap.main(AEADWrap.java:40)
Caused by: java.security.KeyException: Counter exhausted. Reinitialize with new key and/or nonce
at java.base/com.sun.crypto.provider.ChaCha20Cipher.chaCha20Transform(ChaCha20Cipher.java:1046)
at java.base/com.sun.crypto.provider.ChaCha20Cipher$EngineAEADEnc.doUpdate(ChaCha20Cipher.java:1326)
at java.base/com.sun.crypto.provider.ChaCha20Cipher.engineUpdate(ChaCha20Cipher.java:651)
... 3 more
ChaCha20-Poly1305, decryption fails after 2GB with:
java.lang.OutOfMemoryError: Required array length 1073741840 + 1073741840 is too large
at java.base/jdk.internal.util.ArraysSupport.hugeLength(ArraysSupport.java:752)
at java.base/jdk.internal.util.ArraysSupport.newLength(ArraysSupport.java:745)
at java.base/java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:100)
at java.base/java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:132)
at java.base/com.sun.crypto.provider.ChaCha20Cipher$EngineAEADDec.doUpdate(ChaCha20Cipher.java:1392)
at java.base/com.sun.crypto.provider.ChaCha20Cipher.engineUpdate(ChaCha20Cipher.java:651)
at java.base/javax.crypto.Cipher.update(Cipher.java:1869)
at com.test.AEADWrap.crypt(AEADWrap.java:57)
at com.test.AEADWrap.main(AEADWrap.java:46)
AES-GCM encryption fails after 2GB with:
java.security.ProviderException: SunJCE provider only supports input size up to 2147483647 bytes
at java.base/com.sun.crypto.provider.GaloisCounterMode$GCMEncrypt.checkDataLength(GaloisCounterMode.java:1098)
at java.base/com.sun.crypto.provider.GaloisCounterMode$GCMEncrypt.doUpdate(GaloisCounterMode.java:1143)
at java.base/com.sun.crypto.provider.GaloisCounterMode$GCMEncrypt.doUpdate(GaloisCounterMode.java:1120)
at java.base/com.sun.crypto.provider.GaloisCounterMode.engineUpdate(GaloisCounterMode.java:349)
at java.base/javax.crypto.Cipher.update(Cipher.java:1869)
at com.test.AEADWrap.crypt(AEADWrap.java:57)
at com.test.AEADWrap.main(AEADWrap.java:25)
AES-GCM decryption fails after 2GB with:
java.lang.OutOfMemoryError: Required array length 1073741840 + 1073741840 is too large
at java.base/jdk.internal.util.ArraysSupport.hugeLength(ArraysSupport.java:752)
at java.base/jdk.internal.util.ArraysSupport.newLength(ArraysSupport.java:745)
at java.base/java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:100)
at java.base/java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:132)
at java.base/com.sun.crypto.provider.GaloisCounterMode$GCMDecrypt.doUpdate(GaloisCounterMode.java:1458)
at java.base/com.sun.crypto.provider.GaloisCounterMode$GCMDecrypt.doUpdate(GaloisCounterMode.java:1441)
at java.base/com.sun.crypto.provider.GaloisCounterMode.engineUpdate(GaloisCounterMode.java:349)
at java.base/javax.crypto.Cipher.update(Cipher.java:1869)
at com.test.AEADWrap.crypt(AEADWrap.java:57)
at com.test.AEADWrap.main(AEADWrap.java:31)
- relates to
-
JDK-8343339 ChaCha20-Poly1305 out of memory during decryption
-
- Open
-
- links to
-
Commit(master) openjdk/jdk/3e78ff16
-
Review(master) openjdk/jdk/22084