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

DES\CBC\NOPADDING works improperly in some cases

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P4 P4
    • None
    • 6
    • security-libs

      FULL PRODUCT VERSION :
      java version "1.6.0_01"
      Java(TM) SE Runtime Environment (build 1.6.0_01-b06)
      Java HotSpot(TM) Server VM (build 1.6.0_01-b06, mixed mode)


      ADDITIONAL OS VERSION INFORMATION :
      SunOS morpheus 5.10 Generic_118844-26 i86pc i386 i86pc


      A DESCRIPTION OF THE PROBLEM :
      On the Solaris 10 x86 implementation, calling Cipher.update(buffer) with a buffer that does not contain a full block (i.e. size % 8 != 0) will cause the decryption to fail to perform correctly. It works correctly in the Windows 32 bit and Solaris 8 SPARC implementations.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the test program included below

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Output on Win32:
      e7 9e 0e 8e 79 9a fd 0d
      e7 9e 0e 8e 79 9a fd 0d
      e7 9e 0e 8e 79 9a fd 0d


      ACTUAL -
      Output on Solaris 10 x86:

      e7 9e 0e 8e 79 9a fd 0d
      c0 02 06 dd 20 62 12 31
      Exception in thread "main" java.security.ProviderException: update() failed
              at sun.security.pkcs11.P11Cipher.implUpdate(P11Cipher.java:460)
              at sun.security.pkcs11.P11Cipher.engineUpdate(P11Cipher.java:391)
              at sun.security.pkcs11.P11Cipher.engineUpdate(P11Cipher.java:380)
              at javax.crypto.Cipher.update(DashoA13*..)
              at atest.DESFail.decrypt(DESFail.java:70)
              at atest.DESFail.main(DESFail.java:20)
      Caused by: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_BUFFER_TOO_SMALL
              at sun.security.pkcs11.wrapper.PKCS11.C_DecryptUpdate(Native Method)
              at sun.security.pkcs11.P11Cipher.implUpdate(P11Cipher.java:453)
              ... 5 more


      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      See Actual Result

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      package atest;

      import java.util.Arrays;

      import javax.crypto.Cipher;
      import javax.crypto.spec.IvParameterSpec;
      import javax.crypto.spec.SecretKeySpec;

      public class DESFail {
          private static final String DES_KEY = "deadbeefdeadbeef";
          
          public static void main(String[] args) throws Exception {
              // good on Solaris 10 x86
              System.out.println(new DESFail().decrypt(false, false, DES_KEY));
              
              // bad on Solarix 10 x86, good on Win32 and Solaris 8 SPARC
              System.out.println(new DESFail().decrypt(true, false, DES_KEY));

              // exception on Solarix 10 x86, good on Win32 and Solaris 8 SPARC
              System.out.println(new DESFail().decrypt(true, true, DES_KEY));
          }

          public String decrypt(boolean fail, boolean bufferFail, String key) throws Exception {
              byte[] codeBytesMaster = new byte[] {
                      1, 2, 3, 4, 5, 6, 7, 8,
                      9, 10, 11, 12, 13, 14, 15, 16
              };
              byte[] buffer = new byte[1024*1024];
              byte[] keyBytes = hexKeyToBytes(key);
              
              byte[] ivBytes = new byte[8];
              IvParameterSpec iv = new IvParameterSpec(ivBytes);
          
              Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");
              cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyBytes, "DES"), iv);
                  
              // "read" the first buffer of info:
              int first = 1048544 + (fail ? 1 : 0);
              for (int idx = 0; idx < first; idx++) {
                  buffer[idx] = codeBytesMaster[idx % 16];
              }
              {
                  byte[] partA = cipher.update(buffer, 0, first);
              }
              
              // "read" the second buffer of info:
              for (int idx = 0; idx < first; idx++) {
                  buffer[idx] = codeBytesMaster[(idx + (fail ? 1 : 0)) % 16];
              }
              {
                  byte[] partB = cipher.update(buffer, 0, first);
              }
              
              // "read" the third buffer of info:
              for (int idx = 0; idx < first; idx++) {
                  buffer[idx] = codeBytesMaster[(idx + (fail ? 2 : 0)) % 16];
              }
              {
                  byte[] partC = cipher.update(buffer, 0, first);
              }
              
              // "read" the fourth buffer of info
              int second = (fail ? 53781 : 53784);
              for (int idx = 0; idx < second; idx++) {
                  buffer[idx] = codeBytesMaster[(idx + (fail ? 3 : 0)) % 16];
              }
              byte[] partD;
              if (bufferFail) {
                  // this throws an exception
                  partD = cipher.update(buffer, 0, second);
              } else {
                  // this demonstrates decryption failure/corruption
                  for (int loop = 0; loop < 3361; loop++) {
                      partD = cipher.update(buffer, loop * 16, 16);
                  }
                  partD = cipher.update(buffer, 53776, 8);
              }
              
              int ofs = (bufferFail ? 53776 : 0);
              
              return String.format("%02x %02x %02x %02x %02x %02x %02x %02x ",
                      partD[ofs + 0], partD[ofs + 1], partD[ofs + 2], partD[ofs + 3],
                      partD[ofs + 4], partD[ofs + 5], partD[ofs + 6], partD[ofs + 7]);
          }
          
          public static byte[] hexKeyToBytes(String key) throws Exception {
              byte[] kb = new byte[8];
              if (key.length() != 16) {
                  throw new Exception("Key is the wrong length (" + key.length() + " != 16)");
              }
              for (int loop = 0; loop < 8; loop++) {
                  kb[loop] = (byte) Integer.parseInt(key.substring(loop * 2, loop * 2 + 2), 16);
              }
              return kb;
          }

      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      First case of test program -- only Cipher.update() buffers of data that are complete

            valeriep Valerie Peng
            ndcosta Nelson Dcosta (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: