We instantiate the cipher with the following statement:
Cipher cipher = Cipher.getInstance("AES");
SecretKeySpec key = new SecretKeySpec(cipherKey, "AES");
This works in java 7 (1.7_45) but no longer works in Java 8 (1.8_25). We pass the cipher to a CipherInputStream and use the streams to read/write data. The actual exception occurs during close.
EDIT:
A quick look at the JDK code shows that the BadPaddingException is rethrown and in 7 it was ignored:
JDK 7: CipherInputStream.close:
try {
this.cipher.doFinal();
} catch (BadPaddingException var2) {
;
} catch (IllegalBlockSizeException var3) {
;
}
JDK 8: CipherInputStream.close:
try {
if(!this.done) {
this.cipher.doFinal();
}
} catch (IllegalBlockSizeException | BadPaddingException var2) {
if(this.read) {
throw new IOException(var2);
}
}
The question is how to avoid a BadPaddingException in the first place?
EDIT 2:
After doing some research and experimentation we came to the following test program:
public final class CipherSpike2 {
private static final byte[] SECRET_KEY = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
public static void main(String[] args)
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IOException {
encryptDecrypt(511);
encryptDecrypt(512);
}
private static void encryptDecrypt(int i)
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IOException {
byte[] clearText = generateClearText(i);
System.out.println("Clear text length: " + clearText.length);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
CipherOutputStream cos = new CipherOutputStream(bos, getCipher(Cipher.ENCRYPT_MODE));
cos.write(clearText);
cos.close();
final byte[] content = bos.toByteArray();
System.out.println("written bytes: " + content.length);
CipherInputStream
inputStream =
new CipherInputStream(new ByteArrayInputStream(content), getCipher(Cipher.DECRYPT_MODE));
inputStream.read();
inputStream.close();
}
private static byte[] generateClearText(int size) {
return new byte[size];
}
private static Cipher getCipher(int encryptMode)
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKeySpec key = new SecretKeySpec(SECRET_KEY, "AES");
cipher.init(encryptMode, key);
return cipher;
}
}
First, the program writes 511 bytes which results in a 512 byte long "file content". We read exactly one byte. The CipherInputStream reads the data in a 512 byte chunk, so every byte is read and we can close the stream.
Next, we create a content of 512 bytes. This gets padded to 528. If we now read only one byte, we have some bytes left and if we close the stream now it crashes with the given exception.
Now this problem is especially problematic in conjunction with ZipStreams: The encrypted content is in a previous step zipped with a ZipOutputStream and read with a ZipInputStream. It seems, that the ZipInputStream does not consume the same amount of bytes as it has previously written.
It seems that the only solution is to catch the BadPaddingException in the close().(?) From an API view point it seems weird to me, that I cannot close a stream without exception regardless of the number of bytes I've read.
EDIT 3 ZipStream elaboration:
In our application we read a bunch of encrypted text files. So the consturction for the streams looks like this:
BufferedReader/Writer -> InputStreamReader/Writer -> ZipInputStream/Output -> CipherInputStream/Output -> Underlying File Stream
We read the content of the file with a "traditional" while (reader.readLine != null) loop until we reach EOF. After that we try to close the file. But sometimes this results in an exception in Java 8 - see above (-:. It seems, that the ZipOutputStream writes more bytes then the ZipInputStreams consumes, but I don't looked at the code yet.
BadPaddingExceptioncan be triggered by a number of issues, including the wrong key or specifying the wrong padding. Please provide more information about where the encrypted data is coming from and the key. A self-contained example that demonstrates the problem will be ideal. - Duncan Jones