Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8228975

Cannot use ChaCha20-Poly1305 in a CipherInputStream

    XMLWordPrintable

Details

    Description

      ADDITIONAL SYSTEM INFORMATION :
      MacOS X 10.11, but also CentOS 7.
      java version "11.0.1" 2018-10-16 LTS
      Java(TM) SE Runtime Environment 18.9 (build 11.0.1+13-LTS)
      Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.1+13-LTS, mixed mode)

      Also fails on 11.0.4 and 12

      A DESCRIPTION OF THE PROBLEM :
      Trying to use ChaCha20-Poly1305 as cipher for a CipherInputStream always fails with a ShortBufferException.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      The attached source code tests the use of AES/GCM, ChaCha20 and ChaCha20-Poly1305 as parameters for a CipherInputStream. AES/GCM and ChaCha20 work correctly but not ChaCha20-Poly1305.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      ChaCha20-Poly1305 can decrypt correctly.
      ACTUAL -
      ChaCha20-Poly1305 Decryption fails with
      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.Cipher.doFinal(Cipher.java:2085)
      at java.base/javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:125)
      at java.base/javax.crypto.CipherInputStream.read(CipherInputStream.java:242)
      at java.base/java.io.InputStream.readNBytes(InputStream.java:396)
      at java.base/java.io.InputStream.readAllBytes(InputStream.java:333)
      at TestChaCha20.testChaCha20Poly1305(TestChaCha20.java:88)
      at TestChaCha20.main(TestChaCha20.java:31)
      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)
      ... 7 more


      Note that if instead of using readAllBytes(), read(data) is used, the exception is in close():

      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.Cipher.doFinal(Cipher.java:2085)
      at java.base/javax.crypto.CipherInputStream.close(CipherInputStream.java:323)
      at TestChaCha20.testChaCha20Poly1305(TestChaCha20.java:91)
      at TestChaCha20.main(TestChaCha20.java:31)
      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)
      ... 4 more

      In this case the returned byte array is all zeros, as if nothing was actually decrypted.

      ---------- BEGIN SOURCE ----------
      import java.io.ByteArrayInputStream;
      import java.io.ByteArrayOutputStream;
      import java.io.IOException;
      import java.io.InputStream;
      import java.math.BigInteger;
      import java.security.InvalidAlgorithmParameterException;
      import java.security.InvalidKeyException;
      import java.security.NoSuchAlgorithmException;
      import java.security.SecureRandom;
      import java.security.spec.AlgorithmParameterSpec;

      import javax.crypto.BadPaddingException;
      import javax.crypto.Cipher;
      import javax.crypto.CipherInputStream;
      import javax.crypto.CipherOutputStream;
      import javax.crypto.IllegalBlockSizeException;
      import javax.crypto.KeyGenerator;
      import javax.crypto.NoSuchPaddingException;
      import javax.crypto.SecretKey;
      import javax.crypto.spec.ChaCha20ParameterSpec;
      import javax.crypto.spec.GCMParameterSpec;
      import javax.crypto.spec.IvParameterSpec;
      import javax.crypto.spec.SecretKeySpec;

      class TestChaCha20 {
          public static void main(String[] args)
                  throws NoSuchPaddingException, InvalidKeyException, NoSuchAlgorithmException, IOException,
                         BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
              testAESGCM();
              testChaCha20();
              testChaCha20Poly1305();
          }

          static void testAESGCM()
                  throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException,
                         IllegalBlockSizeException, InvalidAlgorithmParameterException, IOException {
              byte[] key = new byte[16];
              byte[] iv = new byte[12];
              SecretKey secretKey = new SecretKeySpec(key, "AES");
              Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
              GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv);
              cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);

              ByteArrayOutputStream out = new ByteArrayOutputStream();
              final CipherOutputStream csout = new CipherOutputStream(out, cipher);
              byte[] clearText = "0123456789".getBytes();
              csout.write(clearText);
              csout.close();
              byte[] cipherText = out.toByteArray();
              System.out.println("AES/GCM Cipher[" + cipherText.length + "]:"
                                         + (new BigInteger(1, cipherText)).toString(16));

              ByteArrayInputStream in = new ByteArrayInputStream(cipherText);
              Cipher icipher = Cipher.getInstance("AES/GCM/NoPadding");
              icipher.init(Cipher.DECRYPT_MODE, secretKey, parameterSpec);
              byte[] data;
              try (InputStream cin = new CipherInputStream(in, icipher)) {
                  data = cin.readAllBytes();
                  System.out.println("AES/GCM Clear[" + data.length + "]:" + (new BigInteger(1, data)).toString(16));
              }
          }

          static void testChaCha20Poly1305()
                  throws InvalidAlgorithmParameterException, InvalidKeyException, NoSuchPaddingException,
                         NoSuchAlgorithmException, IOException, BadPaddingException, IllegalBlockSizeException {
              byte[] key = new byte[32];
              byte[] nonceBytes = new byte[12];
              Cipher cipher = Cipher.getInstance("ChaCha20-Poly1305/None/NoPadding");
              AlgorithmParameterSpec ivParameterSpec = new IvParameterSpec(nonceBytes);
              SecretKeySpec keySpec = new SecretKeySpec(key, "ChaCha20-Poly1305");
              cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivParameterSpec);

              ByteArrayOutputStream out = new ByteArrayOutputStream();
              final CipherOutputStream csout = new CipherOutputStream(out, cipher);
              byte[] clearText = "0123456789".getBytes();
              csout.write(clearText);
              csout.close();
              byte[] cipherText = out.toByteArray();
              System.out.println("ChaCha20-Poly1305 Cipher[" + cipherText.length + "]:"
                                         + (new BigInteger(1, cipherText)).toString(16));

              ByteArrayInputStream in = new ByteArrayInputStream(cipherText);
              Cipher icipher = Cipher.getInstance("ChaCha20-Poly1305/None/NoPadding");
              icipher.init(Cipher.DECRYPT_MODE, keySpec, ivParameterSpec);

              byte[] data;
              try (InputStream csin = new CipherInputStream(in, icipher)) {
                  data = csin.readAllBytes();
                  System.out.println("ChaCha20-Poly1305 Clear[" + data.length + "]:"
                                             + (new BigInteger(1, data)).toString(16));
              }
          }

          static void testChaCha20()
                  throws InvalidAlgorithmParameterException, InvalidKeyException, NoSuchPaddingException,
                         NoSuchAlgorithmException, IOException, BadPaddingException, IllegalBlockSizeException {
              byte[] key = new byte[32];
              byte[] nonceBytes = new byte[12];
              Cipher cipher = Cipher.getInstance("ChaCha20/None/NoPadding");
              ChaCha20ParameterSpec ivParameterSpec = new ChaCha20ParameterSpec(nonceBytes, 1);
              SecretKeySpec keySpec = new SecretKeySpec(key, "ChaCha20");
              cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivParameterSpec);

              ByteArrayOutputStream out = new ByteArrayOutputStream();
              final CipherOutputStream csout = new CipherOutputStream(out, cipher);
              byte[] clearText = "0123456789".getBytes();
              csout.write(clearText);
              csout.close();
              byte[] cipherText = out.toByteArray();
              System.out.println("ChaCha20 Cipher[" + cipherText.length + "]:"
                                         + (new BigInteger(1, cipherText)).toString(16));

              ByteArrayInputStream in = new ByteArrayInputStream(cipherText);
              Cipher icipher = Cipher.getInstance("ChaCha20/None/NoPadding");
              icipher.init(Cipher.DECRYPT_MODE, keySpec, ivParameterSpec);

              byte[] data;
              try (InputStream csin = new CipherInputStream(in, icipher)) {
                  data = csin.readAllBytes();
                  System.out.println("ChaCha20 Clear[" + data.length + "]:"
                                             + (new BigInteger(1, data)).toString(16));
              }
          }
      }
      ---------- END SOURCE ----------

      FREQUENCY : always


      Attachments

        Issue Links

          Activity

            People

              psonal Pallavi Sonal (Inactive)
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: