JDK-8249844 : ChaCha20-Poly1305 TLS cipher suite decryption throws ShortBufferException
  • Type: Bug
  • Component: security-libs
  • Sub-Component: javax.net.ssl
  • Affected Version: 11.0.8-oracle
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_10
  • CPU: x86_64
  • Submitted: 2020-07-16
  • Updated: 2020-07-23
  • Resolved: 2020-07-22
Related Reports
Duplicate :  
Relates :  
Description
ADDITIONAL SYSTEM INFORMATION :
Windows 10 x64 with java version: 11.0.8+10-LTS (OpenJDK)

A DESCRIPTION OF THE PROBLEM :
The bug is described here and marked as solved with version 11.0.8 that was released some days ago: 
https://bugs.openjdk.java.net/browse/JDK-8240146.
Unfortunately the bug is NOT fixed in version 11.08


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
I tested with my own implementation AND with your test available with https://hg.openjdk.java.net/jdk-updates/jdk11u/rev/d5006f145e81


---------- BEGIN SOURCE ----------
https://hg.openjdk.java.net/jdk-updates/jdk11u/rev/d5006f145e81
---------- END SOURCE ----------

FREQUENCY : always



Comments
ILW=MMH=P3
22-07-2020

More response from the submitter: I used this Java version: java version "11.0.8" 2020-07-14 LTS Java(TM) SE Runtime Environment 18.9 (build 11.0.8+10-LTS) Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.8+10-LTS, mixed mode) As a test I used a program written for this error and I found it on description: https://bugs.openjdk.java.net/browse/JDK-8240146 source: https://hg.openjdk.java.net/jdk-updates/jdk11u/rev/d5006f145e81 The error is: java version: 11.0.8+10-LTS CTBuf: java.nio.DirectByteBuffer[pos=1024 lim=1024 cap=2064] PTBuf: java.nio.DirectByteBuffer[pos=1024 lim=2048 cap=2048] Exception in thread "main" java.lang.RuntimeException: javax.crypto.ShortBufferException: Output buffer too small at java.base/com.sun.crypto.provider.ChaCha20Cipher.engineDoFinal(ChaCha20Cipher.java:703) at java.base/javax.crypto.CipherSpi.bufferCrypt(CipherSpi.java:826) at java.base/javax.crypto.CipherSpi.engineDoFinal(CipherSpi.java:730) at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2497) at OutputSizeTest2.testMultiPartAEADDec(OutputSizeTest2.java:141) at OutputSizeTest2.main(OutputSizeTest2.java:49) Caused by: javax.crypto.ShortBufferException: Output buffer too small at java.base/com.sun.crypto.provider.ChaCha20Cipher$EngineAEADDec.doFinal(ChaCha20Cipher.java:1360) at java.base/com.sun.crypto.provider.ChaCha20Cipher.engineDoFinal(ChaCha20Cipher.java:701) ... 5 more Here is the code: import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.spec.ChaCha20ParameterSpec; import javax.crypto.spec.IvParameterSpec; import java.nio.ByteBuffer; import java.security.GeneralSecurityException; import java.security.Key; import java.security.SecureRandom; public class OutputSizeTest2 { private static final SecureRandom SR = new SecureRandom(); public static void main(String args[]) throws Exception { System.out.println("\njava version: " + Runtime.version()); testCC20GetOutSize(); testCC20P1305GetOutSize(); testMultiPartAEADDec(); } // https://bugs.openjdk.java.net/browse/JDK-8240146 // source: https://hg.openjdk.java.net/jdk-updates/jdk11u/rev/d5006f145e81 private static void testCC20GetOutSize() throws GeneralSecurityException { boolean result = true; KeyGenerator kg = KeyGenerator.getInstance("ChaCha20", "SunJCE"); kg.init(256); // ChaCha20 encrypt Cipher cc20 = Cipher.getInstance("ChaCha20", "SunJCE"); cc20.init(Cipher.ENCRYPT_MODE, kg.generateKey(), new ChaCha20ParameterSpec(getRandBuf(12), 10)); testOutLen(cc20, 0, 0); testOutLen(cc20, 5, 5); testOutLen(cc20, 5120, 5120); // perform an update, then test with a final block byte[] input = new byte[5120]; SR.nextBytes(input); cc20.update(input); testOutLen(cc20, 1024, 1024); // Decryption lengths should be calculated the same way as encryption cc20.init(Cipher.DECRYPT_MODE, kg.generateKey(), new ChaCha20ParameterSpec(getRandBuf(12), 10)); testOutLen(cc20, 0, 0); testOutLen(cc20, 5, 5); testOutLen(cc20, 5120, 5120); // perform an update, then test with a final block cc20.update(input); testOutLen(cc20, 1024, 1024); } private static void testCC20P1305GetOutSize() throws GeneralSecurityException { KeyGenerator kg = KeyGenerator.getInstance("ChaCha20", "SunJCE"); kg.init(256); // ChaCha20 encrypt Cipher cc20 = Cipher.getInstance("ChaCha20-Poly1305", "SunJCE"); cc20.init(Cipher.ENCRYPT_MODE, kg.generateKey(), new IvParameterSpec(getRandBuf(12))); // Encryption lengths are calculated as the input length plus the tag // length (16). testOutLen(cc20, 0, 16); testOutLen(cc20, 5, 21); testOutLen(cc20, 5120, 5136); // perform an update, then test with a final block byte[] input = new byte[5120]; SR.nextBytes(input); cc20.update(input); testOutLen(cc20, 1024, 1040); // Decryption lengths are handled differently for AEAD mode. The length // should be zero for anything up to and including the first 16 bytes // (since that's the tag). Anything above that should be the input // length plus any unprocessed input (via update calls), minus the // 16 byte tag. cc20.init(Cipher.DECRYPT_MODE, kg.generateKey(), new IvParameterSpec(getRandBuf(12))); testOutLen(cc20, 0, 0); testOutLen(cc20, 5, 0); testOutLen(cc20, 16, 0); testOutLen(cc20, 5120, 5104); // Perform an update, then test with a the length of a final chunk // of data. cc20.update(input); testOutLen(cc20, 1024, 6128); } private static void testMultiPartAEADDec() throws GeneralSecurityException { KeyGenerator kg = KeyGenerator.getInstance("ChaCha20", "SunJCE"); kg.init(256); Key key = kg.generateKey(); IvParameterSpec ivps = new IvParameterSpec(getRandBuf(12)); // Encrypt some data so we can test decryption. byte[] pText = getRandBuf(2048); ByteBuffer pTextBase = ByteBuffer.wrap(pText); Cipher enc = Cipher.getInstance("ChaCha20-Poly1305", "SunJCE"); enc.init(Cipher.ENCRYPT_MODE, key, ivps); ByteBuffer ctBuf = ByteBuffer.allocateDirect( enc.getOutputSize(pText.length)); enc.doFinal(pTextBase, ctBuf); // Create a new direct plain text ByteBuffer which will catch the // decrypted data. ByteBuffer ptBuf = ByteBuffer.allocateDirect(pText.length); // Set the cipher text buffer limit to roughly half the data so we can // do an update/final sequence. ctBuf.position(0).limit(1024); Cipher dec = Cipher.getInstance("ChaCha20-Poly1305", "SunJCE"); dec.init(Cipher.DECRYPT_MODE, key, ivps); dec.update(ctBuf, ptBuf); System.out.println("CTBuf: " + ctBuf); System.out.println("PTBuf: " + ptBuf); ctBuf.limit(ctBuf.capacity()); dec.doFinal(ctBuf, ptBuf); ptBuf.flip(); pTextBase.flip(); System.out.println("PT Base:" + pTextBase); System.out.println("PT Actual:" + ptBuf); if (pTextBase.compareTo(ptBuf) != 0) { StringBuilder sb = new StringBuilder(); sb.append("Plaintext mismatch: Original: "). append(pTextBase.toString()).append("\nActual :"). append(ptBuf); throw new RuntimeException(sb.toString()); } } private static void testOutLen(Cipher c, int inLen, int expOut) { int actualOut = c.getOutputSize(inLen); /* if (actualOut != expOut) { throw new RuntimeException("Cipher " + c + ", in: " + inLen + ", expOut: " + expOut + ", actual: " + actualOut); } */ } private static byte[] getRandBuf(int len) { byte[] buf = new byte[len]; SR.nextBytes(buf); return buf; } }
22-07-2020

Requested the actual output from java -version or javac -version
20-07-2020

Exception is thrown when executing the test code at https://hg.openjdk.java.net/jdk-updates/jdk11u/rev/d5006f145e81 Exception in thread "main" java.lang.RuntimeException: Cipher javax.crypto.Cipher@2d928643, in: 1024, expOut: 6128, actual: 1008 at TestClass.testOutLen(TestClass.java:289) at TestClass.testCC20P1305GetOutSize(TestClass.java:203) at TestClass.main(TestClass.java:79) Observations: ========== JDK 11.0.8 : Fail JDK 14 : Pass JDK 15 b29 : Pass
17-07-2020