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

CipherInputStream throws BadPaddingException if stream is not fully read

XMLWordPrintable

    • b60
    • generic
    • generic
    • Verified

        FULL PRODUCT VERSION :
        java version "1.8.0_25"
        Java(TM) SE Runtime Environment (build 1.8.0_25-b18)
        Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)

        Same error for:

        java version "1.7.0_71"
        Java(TM) SE Runtime Environment (build 1.7.0_71-b14)
        Java HotSpot(TM) 64-Bit Server VM (build 24.71-b01, mixed mode)


        ADDITIONAL OS VERSION INFORMATION :
        Microsoft Windows [Version 6.1.7601]

        A DESCRIPTION OF THE PROBLEM :
        When reading data from a CipherInputStream a BadPaddingException is thrown when the stream is closed before everything is read.

        REGRESSION. Last worked in version 8u20

        ADDITIONAL REGRESSION INFORMATION:
        java version "1.8.0_20"
        Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
        Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)

        Also worked with:

        java version "1.7.0_67"
        Java(TM) SE Runtime Environment (build 1.7.0_67-b01)
        Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        - Decrypt an InputStream via CipherInputStream
        - Do not read all bytes from the stream
        - Close the CipherInputStream

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        Close without exception
        ACTUAL -
        javax.crypto.BadPaddingException thrown on close

        ERROR MESSAGES/STACK TRACES THAT OCCUR :
        Exception in thread "main" java.io.IOException: javax.crypto.BadPaddingException: Given final block not properly padded
        at javax.crypto.CipherInputStream.close(CipherInputStream.java:321)
        at temp.EncryptionTest.readData(EncryptionTest.java:88)
        at temp.EncryptionTest.main(EncryptionTest.java:23)
        Caused by: javax.crypto.BadPaddingException: Given final block not properly padded
        at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:966)
        at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
        at com.sun.crypto.provider.BlowfishCipher.engineDoFinal(BlowfishCipher.java:319)
        at javax.crypto.Cipher.doFinal(Cipher.java:2004)
        at javax.crypto.CipherInputStream.close(CipherInputStream.java:314)
        ... 2 more

        REPRODUCIBILITY :
        This bug can be reproduced always.

        ---------- BEGIN SOURCE ----------
        package temp;

        import java.io.ByteArrayInputStream;
        import java.io.ByteArrayOutputStream;
        import java.io.InputStream;
        import java.io.OutputStream;
        import java.security.GeneralSecurityException;
        import java.security.SecureRandom;

        import javax.crypto.Cipher;
        import javax.crypto.CipherInputStream;
        import javax.crypto.CipherOutputStream;
        import javax.crypto.KeyGenerator;
        import javax.crypto.spec.IvParameterSpec;
        import javax.crypto.spec.SecretKeySpec;

        public class EncryptionTest
        {
            public static void main(String[] args) throws Throwable
            {
                EncryptionTest t = new EncryptionTest();
                byte[] d = t.wirteData();
                t.readData(d);
            }
            
            final static int COUNT_BYTE_TO_WRITE = 999;
            
            final static int COUNT_BYTE_TO_READ = 99;
            
            final static boolean ENABLE_WORKAROUND = false;
            
            Cipher cipherOut, cipherIn;
            
            SecretKeySpec key;
            
            byte[] iv = new byte[8]; // Blowfish has 8 IV bytes
                                                                    
            public EncryptionTest() throws GeneralSecurityException
            {
                KeyGenerator keygenerator = KeyGenerator.getInstance("Blowfish");
                keygenerator.init(128);
                key = new SecretKeySpec(keygenerator.generateKey().getEncoded(),
                                "Blowfish");
                
                new SecureRandom().nextBytes(iv);
                
                cipherOut = Cipher.getInstance("Blowfish/CBC/PKCS5Padding");
                cipherIn = Cipher.getInstance("Blowfish/CBC/PKCS5Padding");
                
                cipherOut.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
                cipherIn.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
                
            }
            
            public byte[] wirteData() throws Throwable
            {
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                try (OutputStream oute = new CipherOutputStream(baos, cipherOut))
                {
                    for (int i = 0; i < COUNT_BYTE_TO_WRITE; i++)
                        oute.write(0);
                    
                    System.out.println("Write OK");
                }
                return baos.toByteArray();
            }
            
            public void readData(byte[] buf) throws Throwable
            {
                try (InputStream in = new ByteArrayInputStream(buf);
                     InputStream ine = new CipherInputStream(in, cipherIn))
                {
                    for (int i = 0; i < COUNT_BYTE_TO_READ; i++)
                    {
                        int x = ine.read();
                        if (x != 0)
                            throw new RuntimeException("0 !=" + x);
                    }
                    
                    if (ENABLE_WORKAROUND)
                    {// WORKAROUND: ignore all other bytes
                        while (ine.read() >= 0)
                        {
                            while (ine.available() > 0)
                                ine.skip(ine.available());
                        }
                    }
                }
                
                System.out.println("Read OK");
            }
        }

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

        CUSTOMER SUBMITTED WORKAROUND :
        Add the following code before closing:

                       while (ine.read() >= 0)
                        {
                            while (ine.available() > 0)
                                ine.skip(ine.available());
                        }

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

                Created:
                Updated:
                Resolved: