-
Bug
-
Resolution: Won't Fix
-
P3
-
None
-
8u71, 9
-
generic
-
generic
FULL PRODUCT VERSION :
java version "1.8.0_102"
Java(TM) SE Runtime Environment (build 1.8.0_102-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.102-b14, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 10.0.10586]
A DESCRIPTION OF THE PROBLEM :
Retrieving a serialized form of a javax.crypto.SealedObject (using JRE 1.8.0_74 or newer) that was previously sealed using PBEWithHmacSHA256AndAES_256 in JRE 1.8.0_66 (or earlier) will fail with
java.security.InvalidKeyException: Given final block not properly padded
My tests show that the sealing/unsealing cycle works fine when both are performed by a VM that lies in closed range [1.8.0_74, 1.8.0_102] or [1.8.20, 1.8.0_66] (the ranges that I could test).
Hence, the breaking change must have been introduced by 1.8.0_74.
I noted that other PBE algorithms look to be working fine across this point, for example, PBEWithHmacSH1AndAES_128 and PBEWithHmacSH256AndAES_128 had not issue when sealed with 1.8.0_60 and unsealed with 1.8.0_102.
REGRESSION. Last worked in version 8u77
ADDITIONAL REGRESSION INFORMATION:
java version "1.8.0_66"
Java(TM) SE Runtime Environment (build 1.8.0_66-b18)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b18, mixed mode)
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1- Run the test case I've provided named "generateSealedObject()" to obtain the byte[] corresponding to the serialized form of the sealed object, which contains string "test data", using JDK 1.8.0_66 or older.
2- Using the byte array obtained from step 1, run test case named "unsealFailsAfter8u74()" using JDK 1.8.0_66 or older. Confirm that the test passes by retrieving the sealed data,without throwing any exception.
3- Repeat step 2 using JDK 1.8.0_74 or newer. Confirm that the test fails by generating the exception mentioned earlier, "java.security.InvalidKeyException: Given final block not properly padded".
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The test in step 3 should've passed without throwing any exception
ACTUAL -
java.security.InvalidKeyException: Given final block not properly padded
at javax.crypto.SealedObject.getObject(SealedObject.java:260)
at bugs.JavaBugs.unsealFailsAfter8u74(JavaBugs.java:74)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.lang.reflect.Method.invoke(Method.java:498)
ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.security.InvalidKeyException: Given final block not properly padded
at javax.crypto.SealedObject.getObject(SealedObject.java:260)
at bugs.JavaBugs.unsealFailsAfter8u74(JavaBugs.java:74)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.lang.reflect.Method.invoke(Method.java:498)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package bugs;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.fail;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SealedObject;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import org.testng.annotations.Test;
import com.sun.xml.internal.messaging.saaj.util.ByteInputStream;
public class JavaBugs
{
@Test
public void generateSealedObject() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, IOException
{
String data = "test data";
byte[] salt = new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
PBEKeySpec keySpec = new PBEKeySpec("test1234567890".toCharArray());
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBEWithHmacSHA256AndAES_256");
PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 1024 * 16);
SecretKey key = secretKeyFactory.generateSecret(keySpec);
Cipher cipher = Cipher.getInstance("PBEWithHmacSHA256AndAES_256");
cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
SealedObject sealedObject = new SealedObject(data, cipher);
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos))
{
oos.writeObject(sealedObject);
oos.flush();
System.out.println(Arrays.toString(bos.toByteArray()));
}
}
@Test
public void unsealFailsAfter8u74() throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, IOException, ClassNotFoundException
{
PBEKeySpec keySpec = new PBEKeySpec("test1234567890".toCharArray());
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBEWithHmacSHA256AndAES_256");
SecretKey key = secretKeyFactory.generateSecret(keySpec);
SealedObject sealedObject;
Object data;
byte[] sealedObjectBytes = {-84, -19, 0, 5, 115, 114, 0, 25, 106, 97, 118, 97, 120, 46, 99, 114, 121, 112, 116, 111, 46, 83, 101, 97, 108, 101, 100, 79, 98, 106, 101, 99, 116, 62, 54, 61, -90, -61, -73, 84, 112, 2, 0, 4, 91, 0, 13, 101, 110, 99, 111, 100, 101, 100, 80, 97, 114, 97, 109, 115, 116, 0, 2, 91, 66, 91, 0, 16, 101, 110, 99, 114, 121, 112, 116, 101, 100, 67, 111, 110, 116, 101, 110, 116, 113, 0, 126, 0, 1, 76, 0, 9, 112, 97, 114, 97, 109, 115, 65, 108, 103, 116, 0, 18, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 76, 0, 7, 115, 101, 97, 108, 65, 108, 103, 113, 0, 126, 0, 2, 120, 112, 117, 114, 0, 2, 91, 66, -84, -13, 23, -8, 6, 8, 84, -32, 2, 0, 0, 120, 112, 0, 0, 0, 100, 48, 98, 6, 9, 42, -122, 72, -122, -9, 13, 1, 5, 13, 48, 85,
48, 52, 6, 9, 42, -122, 72, -122, -9, 13, 1, 5, 12, 48, 39, 4, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 2, 2, 64, 0, 2, 1, 32, 48, 12, 6, 8, 42, -122, 72, -122, -9, 13, 2, 9, 5, 0, 48, 29, 6, 9, 96, -122, 72, 1, 101, 3, 4, 1, 42, 4, 16,
41, -30, -122, 112, 112, 57, 35, 123, -30, 27, -30, 47, -9, -93, 56, -43, 117, 113, 0, 126, 0, 4, 0, 0, 0, 32, -101, 78, -93, 37, -12, -8, -54, -34, 103, 17, -14, -74, 63, -84, 82, -113, 1, 47, -29, 23, 45, -100, -109, -98, -39, 95, -62, 6, -11, 95, 16, 114, 116, 0, 27, 80, 66, 69, 87, 105, 116, 104, 72, 109, 97, 99, 83, 72, 65, 50, 53, 54, 65, 110, 100, 65, 69, 83, 95, 50, 53, 54, 116, 0, 27, 80, 66, 69, 87, 105, 116, 104, 72, 109, 97, 99, 83, 72, 65, 50, 53, 54, 65, 110, 100, 65, 69, 83, 95, 50, 53, 54};
try (ByteInputStream bis = new ByteInputStream(sealedObjectBytes, sealedObjectBytes.length);
ObjectInputStream ois = new ObjectInputStream(bis))
{
sealedObject = (SealedObject) ois.readObject();
}
data = sealedObject.getObject(key);
assertEquals(data, "test data");
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Nothing.
java version "1.8.0_102"
Java(TM) SE Runtime Environment (build 1.8.0_102-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.102-b14, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 10.0.10586]
A DESCRIPTION OF THE PROBLEM :
Retrieving a serialized form of a javax.crypto.SealedObject (using JRE 1.8.0_74 or newer) that was previously sealed using PBEWithHmacSHA256AndAES_256 in JRE 1.8.0_66 (or earlier) will fail with
java.security.InvalidKeyException: Given final block not properly padded
My tests show that the sealing/unsealing cycle works fine when both are performed by a VM that lies in closed range [1.8.0_74, 1.8.0_102] or [1.8.20, 1.8.0_66] (the ranges that I could test).
Hence, the breaking change must have been introduced by 1.8.0_74.
I noted that other PBE algorithms look to be working fine across this point, for example, PBEWithHmacSH1AndAES_128 and PBEWithHmacSH256AndAES_128 had not issue when sealed with 1.8.0_60 and unsealed with 1.8.0_102.
REGRESSION. Last worked in version 8u77
ADDITIONAL REGRESSION INFORMATION:
java version "1.8.0_66"
Java(TM) SE Runtime Environment (build 1.8.0_66-b18)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b18, mixed mode)
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1- Run the test case I've provided named "generateSealedObject()" to obtain the byte[] corresponding to the serialized form of the sealed object, which contains string "test data", using JDK 1.8.0_66 or older.
2- Using the byte array obtained from step 1, run test case named "unsealFailsAfter8u74()" using JDK 1.8.0_66 or older. Confirm that the test passes by retrieving the sealed data,without throwing any exception.
3- Repeat step 2 using JDK 1.8.0_74 or newer. Confirm that the test fails by generating the exception mentioned earlier, "java.security.InvalidKeyException: Given final block not properly padded".
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The test in step 3 should've passed without throwing any exception
ACTUAL -
java.security.InvalidKeyException: Given final block not properly padded
at javax.crypto.SealedObject.getObject(SealedObject.java:260)
at bugs.JavaBugs.unsealFailsAfter8u74(JavaBugs.java:74)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.lang.reflect.Method.invoke(Method.java:498)
ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.security.InvalidKeyException: Given final block not properly padded
at javax.crypto.SealedObject.getObject(SealedObject.java:260)
at bugs.JavaBugs.unsealFailsAfter8u74(JavaBugs.java:74)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.lang.reflect.Method.invoke(Method.java:498)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package bugs;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.fail;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SealedObject;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import org.testng.annotations.Test;
import com.sun.xml.internal.messaging.saaj.util.ByteInputStream;
public class JavaBugs
{
@Test
public void generateSealedObject() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, IOException
{
String data = "test data";
byte[] salt = new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
PBEKeySpec keySpec = new PBEKeySpec("test1234567890".toCharArray());
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBEWithHmacSHA256AndAES_256");
PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 1024 * 16);
SecretKey key = secretKeyFactory.generateSecret(keySpec);
Cipher cipher = Cipher.getInstance("PBEWithHmacSHA256AndAES_256");
cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
SealedObject sealedObject = new SealedObject(data, cipher);
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos))
{
oos.writeObject(sealedObject);
oos.flush();
System.out.println(Arrays.toString(bos.toByteArray()));
}
}
@Test
public void unsealFailsAfter8u74() throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, IOException, ClassNotFoundException
{
PBEKeySpec keySpec = new PBEKeySpec("test1234567890".toCharArray());
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBEWithHmacSHA256AndAES_256");
SecretKey key = secretKeyFactory.generateSecret(keySpec);
SealedObject sealedObject;
Object data;
byte[] sealedObjectBytes = {-84, -19, 0, 5, 115, 114, 0, 25, 106, 97, 118, 97, 120, 46, 99, 114, 121, 112, 116, 111, 46, 83, 101, 97, 108, 101, 100, 79, 98, 106, 101, 99, 116, 62, 54, 61, -90, -61, -73, 84, 112, 2, 0, 4, 91, 0, 13, 101, 110, 99, 111, 100, 101, 100, 80, 97, 114, 97, 109, 115, 116, 0, 2, 91, 66, 91, 0, 16, 101, 110, 99, 114, 121, 112, 116, 101, 100, 67, 111, 110, 116, 101, 110, 116, 113, 0, 126, 0, 1, 76, 0, 9, 112, 97, 114, 97, 109, 115, 65, 108, 103, 116, 0, 18, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 76, 0, 7, 115, 101, 97, 108, 65, 108, 103, 113, 0, 126, 0, 2, 120, 112, 117, 114, 0, 2, 91, 66, -84, -13, 23, -8, 6, 8, 84, -32, 2, 0, 0, 120, 112, 0, 0, 0, 100, 48, 98, 6, 9, 42, -122, 72, -122, -9, 13, 1, 5, 13, 48, 85,
48, 52, 6, 9, 42, -122, 72, -122, -9, 13, 1, 5, 12, 48, 39, 4, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 2, 2, 64, 0, 2, 1, 32, 48, 12, 6, 8, 42, -122, 72, -122, -9, 13, 2, 9, 5, 0, 48, 29, 6, 9, 96, -122, 72, 1, 101, 3, 4, 1, 42, 4, 16,
41, -30, -122, 112, 112, 57, 35, 123, -30, 27, -30, 47, -9, -93, 56, -43, 117, 113, 0, 126, 0, 4, 0, 0, 0, 32, -101, 78, -93, 37, -12, -8, -54, -34, 103, 17, -14, -74, 63, -84, 82, -113, 1, 47, -29, 23, 45, -100, -109, -98, -39, 95, -62, 6, -11, 95, 16, 114, 116, 0, 27, 80, 66, 69, 87, 105, 116, 104, 72, 109, 97, 99, 83, 72, 65, 50, 53, 54, 65, 110, 100, 65, 69, 83, 95, 50, 53, 54, 116, 0, 27, 80, 66, 69, 87, 105, 116, 104, 72, 109, 97, 99, 83, 72, 65, 50, 53, 54, 65, 110, 100, 65, 69, 83, 95, 50, 53, 54};
try (ByteInputStream bis = new ByteInputStream(sealedObjectBytes, sealedObjectBytes.length);
ObjectInputStream ois = new ObjectInputStream(bis))
{
sealedObject = (SealedObject) ois.readObject();
}
data = sealedObject.getObject(key);
assertEquals(data, "test data");
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Nothing.