-
Bug
-
Resolution: Not an Issue
-
P3
-
None
-
7u80, 8u45, 9
(Transferring from JCE/AES: The base 64 decoding is causing byte arrays to be created that are not a multiple of 16, which is required for AES. Details in the currently 4th comment).
FULL PRODUCT VERSION :
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Reproduced on multiple OSes, including Linux (CentOS 7) and MacOS 10.10:
Linux localhost.localdomain 3.10.0-229.14.1.el7.x86_64 #1 SMP Tue Sep 15 15:05:51 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
Darwin localhost.localdomain 14.5.0 Darwin Kernel Version 14.5.0: Wed Jul 29 02:26:53 PDT 2015; root:xnu-2782.40.9~1/RELEASE_X86_64 x86_64
EXTRA RELEVANT SYSTEM CONFIGURATION :
Reproduction of the issue has been achieved on several systems and VMs. It does not appear to be host or OS specific.
A DESCRIPTION OF THE PROBLEM :
The AES cipher APIs throw "IllegalBlockSize" exceptions on recent 1.8 (and 1.7) JVM/JDK editions. When the AES cipher is given a block of data to encrypt or decrypt the library will throw an exception when the data block is not a multiple of 16 bytes in size. The problem is particularly an issue when stream readers wrap the Cipher APIs and the block size can not be controlled. Older JVM/JDKs worked fine, the issue was introduced recently.
This has been reported before, here: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8075224 but that test driver was incomplete and not generic enough to reproduce the issue. We are seeing this issue in our calls to AES and have attached a re-factored test driver that shows the issue clearly.
REGRESSION. Last worked in version 7u75
ADDITIONAL REGRESSION INFORMATION:
Here's a report of what versions work with the attached test driver and what versions do not work:
[spadmin@localhost ~]$ ./runJvmVersionTests.sh
Testing against JDK Version: jdk1.7.0_15
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.7.0_15
Decrypted payload from file: <?xml version="1.0" encoding="UTF-8"?><YESEFTTransactionLog><BatchNo>0</BatchNo><TotalCredits>0</TotalCredits><TotalDebits>0</TotalDebits><CreditNoTrans>0</CreditNoTrans><DebitNoTrans>0</DebitNoTrans><DeclinedNoTrans>0</Dec
Testing against JDK Version: jdk1.7.0_45
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.7.0_45
Decrypted payload from file: <?xml version="1.0" encoding="UTF-8"?><YESEFTTransactionLog><BatchNo>0</BatchNo><TotalCredits>0</TotalCredits><TotalDebits>0</TotalDebits><CreditNoTrans>0</CreditNoTrans><DebitNoTrans>0</DebitNoTrans><DeclinedNoTrans>0</Dec
Testing against JDK Version: jdk1.7.0_51
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.7.0_51
Decrypted payload from file: <?xml version="1.0" encoding="UTF-8"?><YESEFTTransactionLog><BatchNo>0</BatchNo><TotalCredits>0</TotalCredits><TotalDebits>0</TotalDebits><CreditNoTrans>0</CreditNoTrans><DebitNoTrans>0</DebitNoTrans><DeclinedNoTrans>0</Dec
Testing against JDK Version: jdk1.7.0_75
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.7.0_75
FAIL: IllegalBlockSizeException on 1.7.0_75
Testing against JDK Version: jdk1.7.0_79
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.7.0_79
FAIL: IllegalBlockSizeException on 1.7.0_79
Testing against JDK Version: jdk1.7.0_80
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.7.0_80
FAIL: IllegalBlockSizeException on 1.7.0_80
Testing against JDK Version: jdk1.8.0_05
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.8.0_05
Decrypted payload from file: <?xml version="1.0" encoding="UTF-8"?><YESEFTTransactionLog><BatchNo>0</BatchNo><TotalCredits>0</TotalCredits><TotalDebits>0</TotalDebits><CreditNoTrans>0</CreditNoTrans><DebitNoTrans>0</DebitNoTrans><DeclinedNoTrans>0</Dec
Testing against JDK Version: jdk1.8.0_11
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.8.0_11
Decrypted payload from file: <?xml version="1.0" encoding="UTF-8"?><YESEFTTransactionLog><BatchNo>0</BatchNo><TotalCredits>0</TotalCredits><TotalDebits>0</TotalDebits><CreditNoTrans>0</CreditNoTrans><DebitNoTrans>0</DebitNoTrans><DeclinedNoTrans>0</Dec
Testing against JDK Version: jdk1.8.0_31
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.8.0_31
FAIL: IllegalBlockSizeException on 1.8.0_31
Testing against JDK Version: jdk1.8.0_40
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.8.0_40
FAIL: IllegalBlockSizeException on 1.8.0_40
Testing against JDK Version: jdk1.8.0_51
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.8.0_51
FAIL: IllegalBlockSizeException on 1.8.0_51
Testing against JDK Version: jdk1.8.0_60
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.8.0_60
FAIL: IllegalBlockSizeException on 1.8.0_60
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached test driver program. It will fail on JVM/JDKs that do not handle oddly sized data blocks.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The code should run correctly and successfully on all JVM/JDK versions. The Cipher API for AES encryption should handle oddly sized data blocks.
ACTUAL -
Test driver fails on JVM/JDK versions that have a problem with the following stack trace:
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.8.0_25
java.io.IOException: javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:115)
at javax.crypto.CipherInputStream.read(CipherInputStream.java:233)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at JVMAESEncryptionTest.main(JVMAESEncryptionTest.java:127)
Caused by: javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:913)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:436)
at javax.crypto.Cipher.doFinal(Cipher.java:2004)
at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:112)
... 9 more
Error while reading data from encyrpted file.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.io.IOException: javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:115)
at javax.crypto.CipherInputStream.read(CipherInputStream.java:233)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at JVMAESEncryptionTest.main(JVMAESEncryptionTest.java:127)
Caused by: javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:913)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:436)
at javax.crypto.Cipher.doFinal(Cipher.java:2004)
at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:112)
... 9 more
Error while reading data from encyrpted file.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.io.*;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.spec.KeySpec;
import java.util.*;
import javax.crypto.*;
import javax.crypto.*;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* This is related to the following Oracle bug details:
*
* bugs.java.com/bugdatabase/view_bug.do?bug_id=8075224
*
* @author adam.hampton
*
*/
public class JVMAESEncryptionTest {
public JVMAESEncryptionTest() {
// TODO Auto-generated constructor stub
}
// Code to convert a hex string to a byte array.
// Credit for this quick & dirty implementation goes to:
// http://stackoverflow.com/questions/140131/convert-a-string-representation-of-a-hex-dump-to-a-byte-array-using-java
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
public static void main(String[] args) {
String jvmVersion = System.getProperty("java.version");
String newLineSep = System.getProperty("line.separator");
System.out.println("JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:" + jvmVersion);
// Example Baste64 encoded, encrypted data.
ArrayList<String> encryptedPayloadLines = new ArrayList<String>();
encryptedPayloadLines.add("adP2rz4phDL01MmgPz/B+QoWvWr8UAwKcBNOVcDOvbHI1tIpIaW5a+Vyd8eK6K2WW2mjyhrhIGI9");
encryptedPayloadLines.add("TeL552EnzKmOjefkCV8miv1yxUG+TfshXNVlaS5n4xHQ178cnsqyOylg0HoOGOIGBwE/HMEo1jlf");
encryptedPayloadLines.add("l/+bRy7o8j5+ruDvqs4ztSnG/lj09dCIvkOSUS454adFtllpYATyWSQLBesNbqWrerDKH52GTBiR");
encryptedPayloadLines.add("3OvXyYGAqdlah3iN4MQ56B8HtOZt3CD9y+v0lhYmVHeBrVZ0m5+b2EG12xDBCezy7JitALQP/175");
encryptedPayloadLines.add("pt9+rbQLDBMJKvd7DKZs");
StringBuilder fullB64DataSB = new StringBuilder();
for (String lineFromFile : encryptedPayloadLines) {
fullB64DataSB.append(lineFromFile);
}
String fullB64Data = fullB64DataSB.toString();
// Convert the Base64 encoded payload into an array of byte data.
// This is a headache because we want to test against all of the
// 1.6, 1.7, 1.8 and 1.9 JVMs here and the Base64.Decoder package did
// not appear until 1.8. Sigh.
byte [] decodedB64 = javax.xml.bind.DatatypeConverter.parseBase64Binary(fullB64Data);
// Used for sanity checking the base 64 decoding:
int testFlag = 0;
if (testFlag != 0) {
System.out.println("Original b64 string size: " + fullB64Data.length());
System.out.println("Decoded payload size: " + decodedB64.length);
for (int i=0;i<decodedB64.length;i++) {
byte thisByte = decodedB64[i];
System.out.print(Integer.toHexString(thisByte));
}
System.out.println();
}
String fileEncryptionKey = "C9063155B07A542BD678B1E2969C1B775E47BFA9";
byte[] deskeydata = hexStringToByteArray(fileEncryptionKey);
deskeydata = Arrays.copyOf(deskeydata, 16);
SecretKeySpec secretKey = new SecretKeySpec(deskeydata, "AES");
// Declare an initialization vector.
byte[] newiv = new byte [] { (byte)99, (byte)126, (byte)11, (byte)-10, (byte)-128, (byte)-58, (byte)-122, (byte)-16, (byte)-48, (byte)-82, (byte)40, (byte)69, (byte)52, (byte)-121, (byte)121, (byte)88 };
IvParameterSpec ivspec = new IvParameterSpec(newiv);
Cipher c;
try {
c = Cipher.getInstance("AES/CBC/PKCS5Padding");
c.init(2, secretKey, ivspec);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e) {
e.printStackTrace();
System.err.println("Failed to construct Cipher object.");
return;
}
// Process the example B64 decoded data from RAM.
InputStream is = new ByteArrayInputStream(decodedB64);
CipherInputStream ci = new CipherInputStream(is, c);
InputStreamReader reader;
BufferedReader br;
try {
reader = new InputStreamReader(ci, "UTF-8");
br = new BufferedReader(reader);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
System.err.println("Failed to construct a reader for encrypted stream");
return;
}
String xmlString = "";
StringBuilder xmlData = new StringBuilder();
try {
while ( (xmlString = br.readLine()) != null) {
xmlData.append(xmlString);
}
reader.close();
ci.close();
br.close();
} catch (IOException e) {
/*
if (e.getMessage().contains("IllegalBlockSizeException")) {
System.err.println("FAIL: IllegalBlockSizeException on JVM " + jvmVersion);
System.exit(1);
}
*/
e.printStackTrace();
System.err.println("Error while reading data from encyrpted file.");
return;
}
System.out.println("Decrypted payload from file: " + xmlData.toString());
return;
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
There are no workarounds for code that needs to use a stream to pass data to an AES Cipher.
For code that encodes its own AES payloads block-by-block the caller must ensure it passes a 16 byte aligned byte array to the Cipher APIs.
SUPPORT :
YES
FULL PRODUCT VERSION :
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Reproduced on multiple OSes, including Linux (CentOS 7) and MacOS 10.10:
Linux localhost.localdomain 3.10.0-229.14.1.el7.x86_64 #1 SMP Tue Sep 15 15:05:51 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
Darwin localhost.localdomain 14.5.0 Darwin Kernel Version 14.5.0: Wed Jul 29 02:26:53 PDT 2015; root:xnu-2782.40.9~1/RELEASE_X86_64 x86_64
EXTRA RELEVANT SYSTEM CONFIGURATION :
Reproduction of the issue has been achieved on several systems and VMs. It does not appear to be host or OS specific.
A DESCRIPTION OF THE PROBLEM :
The AES cipher APIs throw "IllegalBlockSize" exceptions on recent 1.8 (and 1.7) JVM/JDK editions. When the AES cipher is given a block of data to encrypt or decrypt the library will throw an exception when the data block is not a multiple of 16 bytes in size. The problem is particularly an issue when stream readers wrap the Cipher APIs and the block size can not be controlled. Older JVM/JDKs worked fine, the issue was introduced recently.
This has been reported before, here: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8075224 but that test driver was incomplete and not generic enough to reproduce the issue. We are seeing this issue in our calls to AES and have attached a re-factored test driver that shows the issue clearly.
REGRESSION. Last worked in version 7u75
ADDITIONAL REGRESSION INFORMATION:
Here's a report of what versions work with the attached test driver and what versions do not work:
[spadmin@localhost ~]$ ./runJvmVersionTests.sh
Testing against JDK Version: jdk1.7.0_15
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.7.0_15
Decrypted payload from file: <?xml version="1.0" encoding="UTF-8"?><YESEFTTransactionLog><BatchNo>0</BatchNo><TotalCredits>0</TotalCredits><TotalDebits>0</TotalDebits><CreditNoTrans>0</CreditNoTrans><DebitNoTrans>0</DebitNoTrans><DeclinedNoTrans>0</Dec
Testing against JDK Version: jdk1.7.0_45
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.7.0_45
Decrypted payload from file: <?xml version="1.0" encoding="UTF-8"?><YESEFTTransactionLog><BatchNo>0</BatchNo><TotalCredits>0</TotalCredits><TotalDebits>0</TotalDebits><CreditNoTrans>0</CreditNoTrans><DebitNoTrans>0</DebitNoTrans><DeclinedNoTrans>0</Dec
Testing against JDK Version: jdk1.7.0_51
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.7.0_51
Decrypted payload from file: <?xml version="1.0" encoding="UTF-8"?><YESEFTTransactionLog><BatchNo>0</BatchNo><TotalCredits>0</TotalCredits><TotalDebits>0</TotalDebits><CreditNoTrans>0</CreditNoTrans><DebitNoTrans>0</DebitNoTrans><DeclinedNoTrans>0</Dec
Testing against JDK Version: jdk1.7.0_75
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.7.0_75
FAIL: IllegalBlockSizeException on 1.7.0_75
Testing against JDK Version: jdk1.7.0_79
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.7.0_79
FAIL: IllegalBlockSizeException on 1.7.0_79
Testing against JDK Version: jdk1.7.0_80
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.7.0_80
FAIL: IllegalBlockSizeException on 1.7.0_80
Testing against JDK Version: jdk1.8.0_05
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.8.0_05
Decrypted payload from file: <?xml version="1.0" encoding="UTF-8"?><YESEFTTransactionLog><BatchNo>0</BatchNo><TotalCredits>0</TotalCredits><TotalDebits>0</TotalDebits><CreditNoTrans>0</CreditNoTrans><DebitNoTrans>0</DebitNoTrans><DeclinedNoTrans>0</Dec
Testing against JDK Version: jdk1.8.0_11
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.8.0_11
Decrypted payload from file: <?xml version="1.0" encoding="UTF-8"?><YESEFTTransactionLog><BatchNo>0</BatchNo><TotalCredits>0</TotalCredits><TotalDebits>0</TotalDebits><CreditNoTrans>0</CreditNoTrans><DebitNoTrans>0</DebitNoTrans><DeclinedNoTrans>0</Dec
Testing against JDK Version: jdk1.8.0_31
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.8.0_31
FAIL: IllegalBlockSizeException on 1.8.0_31
Testing against JDK Version: jdk1.8.0_40
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.8.0_40
FAIL: IllegalBlockSizeException on 1.8.0_40
Testing against JDK Version: jdk1.8.0_51
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.8.0_51
FAIL: IllegalBlockSizeException on 1.8.0_51
Testing against JDK Version: jdk1.8.0_60
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.8.0_60
FAIL: IllegalBlockSizeException on 1.8.0_60
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached test driver program. It will fail on JVM/JDKs that do not handle oddly sized data blocks.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The code should run correctly and successfully on all JVM/JDK versions. The Cipher API for AES encryption should handle oddly sized data blocks.
ACTUAL -
Test driver fails on JVM/JDK versions that have a problem with the following stack trace:
JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:1.8.0_25
java.io.IOException: javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:115)
at javax.crypto.CipherInputStream.read(CipherInputStream.java:233)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at JVMAESEncryptionTest.main(JVMAESEncryptionTest.java:127)
Caused by: javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:913)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:436)
at javax.crypto.Cipher.doFinal(Cipher.java:2004)
at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:112)
... 9 more
Error while reading data from encyrpted file.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.io.IOException: javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:115)
at javax.crypto.CipherInputStream.read(CipherInputStream.java:233)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at JVMAESEncryptionTest.main(JVMAESEncryptionTest.java:127)
Caused by: javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:913)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:436)
at javax.crypto.Cipher.doFinal(Cipher.java:2004)
at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:112)
... 9 more
Error while reading data from encyrpted file.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.io.*;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.spec.KeySpec;
import java.util.*;
import javax.crypto.*;
import javax.crypto.*;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* This is related to the following Oracle bug details:
*
* bugs.java.com/bugdatabase/view_bug.do?bug_id=8075224
*
* @author adam.hampton
*
*/
public class JVMAESEncryptionTest {
public JVMAESEncryptionTest() {
// TODO Auto-generated constructor stub
}
// Code to convert a hex string to a byte array.
// Credit for this quick & dirty implementation goes to:
// http://stackoverflow.com/questions/140131/convert-a-string-representation-of-a-hex-dump-to-a-byte-array-using-java
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
public static void main(String[] args) {
String jvmVersion = System.getProperty("java.version");
String newLineSep = System.getProperty("line.separator");
System.out.println("JVM AES Encryption Test, Oracle Java bug 8075224 - java.version:" + jvmVersion);
// Example Baste64 encoded, encrypted data.
ArrayList<String> encryptedPayloadLines = new ArrayList<String>();
encryptedPayloadLines.add("adP2rz4phDL01MmgPz/B+QoWvWr8UAwKcBNOVcDOvbHI1tIpIaW5a+Vyd8eK6K2WW2mjyhrhIGI9");
encryptedPayloadLines.add("TeL552EnzKmOjefkCV8miv1yxUG+TfshXNVlaS5n4xHQ178cnsqyOylg0HoOGOIGBwE/HMEo1jlf");
encryptedPayloadLines.add("l/+bRy7o8j5+ruDvqs4ztSnG/lj09dCIvkOSUS454adFtllpYATyWSQLBesNbqWrerDKH52GTBiR");
encryptedPayloadLines.add("3OvXyYGAqdlah3iN4MQ56B8HtOZt3CD9y+v0lhYmVHeBrVZ0m5+b2EG12xDBCezy7JitALQP/175");
encryptedPayloadLines.add("pt9+rbQLDBMJKvd7DKZs");
StringBuilder fullB64DataSB = new StringBuilder();
for (String lineFromFile : encryptedPayloadLines) {
fullB64DataSB.append(lineFromFile);
}
String fullB64Data = fullB64DataSB.toString();
// Convert the Base64 encoded payload into an array of byte data.
// This is a headache because we want to test against all of the
// 1.6, 1.7, 1.8 and 1.9 JVMs here and the Base64.Decoder package did
// not appear until 1.8. Sigh.
byte [] decodedB64 = javax.xml.bind.DatatypeConverter.parseBase64Binary(fullB64Data);
// Used for sanity checking the base 64 decoding:
int testFlag = 0;
if (testFlag != 0) {
System.out.println("Original b64 string size: " + fullB64Data.length());
System.out.println("Decoded payload size: " + decodedB64.length);
for (int i=0;i<decodedB64.length;i++) {
byte thisByte = decodedB64[i];
System.out.print(Integer.toHexString(thisByte));
}
System.out.println();
}
String fileEncryptionKey = "C9063155B07A542BD678B1E2969C1B775E47BFA9";
byte[] deskeydata = hexStringToByteArray(fileEncryptionKey);
deskeydata = Arrays.copyOf(deskeydata, 16);
SecretKeySpec secretKey = new SecretKeySpec(deskeydata, "AES");
// Declare an initialization vector.
byte[] newiv = new byte [] { (byte)99, (byte)126, (byte)11, (byte)-10, (byte)-128, (byte)-58, (byte)-122, (byte)-16, (byte)-48, (byte)-82, (byte)40, (byte)69, (byte)52, (byte)-121, (byte)121, (byte)88 };
IvParameterSpec ivspec = new IvParameterSpec(newiv);
Cipher c;
try {
c = Cipher.getInstance("AES/CBC/PKCS5Padding");
c.init(2, secretKey, ivspec);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e) {
e.printStackTrace();
System.err.println("Failed to construct Cipher object.");
return;
}
// Process the example B64 decoded data from RAM.
InputStream is = new ByteArrayInputStream(decodedB64);
CipherInputStream ci = new CipherInputStream(is, c);
InputStreamReader reader;
BufferedReader br;
try {
reader = new InputStreamReader(ci, "UTF-8");
br = new BufferedReader(reader);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
System.err.println("Failed to construct a reader for encrypted stream");
return;
}
String xmlString = "";
StringBuilder xmlData = new StringBuilder();
try {
while ( (xmlString = br.readLine()) != null) {
xmlData.append(xmlString);
}
reader.close();
ci.close();
br.close();
} catch (IOException e) {
/*
if (e.getMessage().contains("IllegalBlockSizeException")) {
System.err.println("FAIL: IllegalBlockSizeException on JVM " + jvmVersion);
System.exit(1);
}
*/
e.printStackTrace();
System.err.println("Error while reading data from encyrpted file.");
return;
}
System.out.println("Decrypted payload from file: " + xmlData.toString());
return;
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
There are no workarounds for code that needs to use a stream to pass data to an AES Cipher.
For code that encodes its own AES payloads block-by-block the caller must ensure it passes a 16 byte aligned byte array to the Cipher APIs.
SUPPORT :
YES
- relates to
-
JDK-8075224 IllegalBlockSizeException: Input length must be multiple of 16 when decrypting
- Closed