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

Broken crypto algorithm PBEWithHmacSHA256AndAES_256

    XMLWordPrintable

Details

    • generic
    • generic

    Description

      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.

      Attachments

        Activity

          People

            vinnie Vincent Ryan
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: