-
Bug
-
Resolution: Not an Issue
-
P4
-
8u40
-
x86_64
-
windows_7
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
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