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

CipherOutputStream silently drops underlying Cipher's Exception

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Not an Issue
    • Icon: P4 P4
    • 9
    • 8u40
    • security-libs

      FULL PRODUCT VERSION :
      java version "1.8.0_40"
      Java(TM) SE Runtime Environment (build 1.8.0_40-b26)
      Java HotSpot(TM) 64-Bit Server VM (build 25.40-b25, mixed mode)


      ADDITIONAL OS VERSION INFORMATION :
      Windows 7 64 bits
      Not specific to windows Java source code

      A DESCRIPTION OF THE PROBLEM :
      Cipher in NoPadding mode must be inputed a byte array of size n * cipher.getBlockSize().
      If not the case, whe have different behaviour with CipherInputStream an CipherOutputStream :
      - CipherInputStream rethrows an IOException when the underlying Cipher throws a IllegalBlockSizeException and BadPaddingException
      - CipherOutputStream silently drop theses exception IllegalBlockSizeException and BadPaddingException in the same situation.


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      throws IOException()
      ACTUAL -
      Encryption failed but no exception occured

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.io.ByteArrayInputStream;
      import java.io.ByteArrayOutputStream;
      import java.io.IOException;
      import java.security.GeneralSecurityException;
      import java.security.Key;
      import java.util.Arrays;

      import javax.crypto.Cipher;
      import javax.crypto.CipherInputStream;
      import javax.crypto.CipherOutputStream;
      import javax.crypto.KeyGenerator;

      public class TestCipherOutputStream {

          public static byte[] encryptCipherOutputStream(Key key, byte[] input) throws GeneralSecurityException, IOException {
              ByteArrayOutputStream bos = new ByteArrayOutputStream();

              Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");

              cipher.init(Cipher.ENCRYPT_MODE, key);
              CipherOutputStream cos = new CipherOutputStream(bos, cipher);
              cos.write(input);
              // cos.close should throw an IOException on BadPaddingException
              cos.close();
              return bos.toByteArray();

          }

          public static byte[] encryptCipherInputStream(Key key, byte[] input) throws GeneralSecurityException, IOException {
              Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
              cipher.init(Cipher.ENCRYPT_MODE, key);
              CipherInputStream cis = new CipherInputStream(new ByteArrayInputStream(input), cipher);
              byte[] outBuffer = new byte[1024];
              int bytesRead = cis.read(outBuffer);
              cis.close();
              byte[] ret = new byte[bytesRead];
              System.arraycopy(outBuffer, 0, ret, 0, bytesRead);
              return ret;

          }

          public static void main(String[] args) throws Exception {
              KeyGenerator kgen = KeyGenerator.getInstance("AES");
              Key key = kgen.generateKey();

              byte[] toEncryptOk = new byte[16];

              System.out.println("Cipher of cipher.getBlockSize byte will pass");
              byte[] encOk1 = encryptCipherOutputStream(key, toEncryptOk);
              byte[] encOk2 = encryptCipherInputStream(key, toEncryptOk);
              assert (Arrays.equals(encOk1, encOk2));

              // Problematic behavior
              byte[] toEncryptShouldAlwaysFailed = new byte[15];

              byte[] encKo1 = null, encKo2 = null;
              try {
                  System.out.println("Cipher of less than cipher.getBlockSize should fail...");
                  encKo1 = encryptCipherOutputStream(key, toEncryptShouldAlwaysFailed);
                  System.out.println("Drop silently IllegalBlockSizeException");
              } catch (IOException ex) {
                  System.out.println("Never append");
              }
              try {
                  System.out.println("Cipher of less than cipher.getBlockSize will fail...");
                  encKo2 = encryptCipherInputStream(key, toEncryptShouldAlwaysFailed);
                  System.out.println("Never append");
              } catch (IOException ex) {
                  System.out.println("and fail... Different way of handling IllegalBlockSizeException and BadPaddingException");
              }

              assert (Arrays.equals(encKo1, encKo2));
          }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Create an Exception Aware CipherOutputStream from JDK source code

            ascarpino Anthony Scarpino
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: