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

javax.crypto.spec.SecretKeySpec constructor bug (in implementation AND SPEC)

XMLWordPrintable

      FULL PRODUCT VERSION :
      java version " 1.7.0_15 "
      Java(TM) SE Runtime Environment (build 1.7.0_15-b03)
      Java HotSpot(TM) 64-Bit Server VM (build 23.7-b01, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      12.4.0 Darwin Kernel Version 12.4.0: Wed May 1 17:57:12 PDT 2013; root:xnu-2050.24.15~1/RELEASE_X86_64 x86_64

      EXTRA RELEVANT SYSTEM CONFIGURATION :
      configuration irrelevant, this is a bug in the specification (which is implemented, therefore also a bug in the implementation)

      A DESCRIPTION OF THE PROBLEM :
      javax.crypto.spec.SecretKeySpec does not properly support empty keys.
      it is documented as such in the javadoc, and implementation is true to that documentation.
      Please note that an empty security key SHOULD be allowed, and is not characteristically disallowed by many crypto specs.

      In particular, I am testing HMAC implementations and Wikipedia's article includes as one of its two reference examples the HMAC of an empty message using an empty secret key.
      https://en.wikipedia.org/wiki/Hash-based_message_authentication_code#Examples_of_HMAC_.28MD5.2C_SHA1.2C_SHA256.29

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      System.out.println(new javax.crypto.spec.SecretKeySpec(new byte[0], " HmacSHA256 " ));

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      javax.crypto.spec.SecretKeySpec@########
      ACTUAL -
      Exception in thread " main " java.lang.IllegalArgumentException: Empty key
      at javax.crypto.spec.SecretKeySpec.<init>(SecretKeySpec.java:96)

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      Exception in thread " main " java.lang.IllegalArgumentException: Empty key
      at javax.crypto.spec.SecretKeySpec.<init>(SecretKeySpec.java:96)

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------

      import javax.crypto.Mac;
      import javax.crypto.spec.SecretKeySpec;
      import java.security.Key;
      import java.util.Arrays;

      /**
       * exhibiting a bug in Java's crypto SecretKeySpec specification (and therefore implementation)
       */
      public class CryptoBug {
      static final boolean WORKAROUND = false;

      public static void main(String[] args) throws Exception {
      String
      enc = " UTF8 " ,
      alg = " HmacSHA256 " ;


      byte[] result,
      /*
       * HMAC_SHA256( " key " , " The quick brown fox jumps over the lazy dog " ) = 0xf7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8
       * SOURCE: https://en.wikipedia.org/wiki/Hash-based_message_authentication_code#Examples_of_HMAC_.28MD5.2C_SHA1.2C_SHA256.29
       */
      result1 = {-9, -68, -125, -12, 48, 83, -124, 36, -79, 50, -104, -26, -86, 111, -79, 67, -17, 77, 89, -95, 73, 70, 23, 89, -105, 71, -99, -68, 45, 26, 60, -40},
      /*
       * HMAC_SHA256( " " , " " ) = 0xb613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad
       * SOURCE: https://en.wikipedia.org/wiki/Hash-based_message_authentication_code#Examples_of_HMAC_.28MD5.2C_SHA1.2C_SHA256.29
       */
      result2 = {-74, 19, 103, -102, 8, 20, -39, -20, 119, 47, -107, -41, 120, -61, 95, -59, -1, 22, -105, -60, -109, 113, 86, 83, -58, -57, 18, 20, 66, -110, -59, -83};

      /* this example always works */
      result = hmac(enc, alg, " key " , " The quick brown fox jumps over the lazy dog " );
      System.out.println(Arrays.toString(result));
      if (Arrays.equals(result, result1))
      System.out.println( " success: result == result1 " );
      else
      throw new Exception( " result != result1 " );

      /* this example fails, but works with work-around */
      result = hmac(enc, alg, " " , " " );
      System.out.println(Arrays.toString(result));
      if (Arrays.equals(result, result2))
      System.out.println( " success: result == result2 " );
      else
      throw new Exception( " result != result2 " );
      }

      static byte[] hmac(String enc, String alg, String key, String msg) throws Exception {
      Key k = getSecretKey(enc, alg, key);
      Mac m = Mac.getInstance(alg);
      m.init(k);
      return m.doFinal(msg.getBytes(enc));
      }

      static Key getSecretKey(String enc, String alg, String key) throws Exception {
      if (WORKAROUND && key.isEmpty())
      return new SecretKeySpec(new byte[] {0}, 1, 0, alg);

      return new SecretKeySpec(key.getBytes(enc), alg);
      }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      If an empty key is needed, use SecretKeySpec's second constructor with a dummy, NON-EMPTY key, but with offset of its full length and length of 0.

      byte[] dummy = ...; // any non-zero-length array
      Key k = new SecretKeySpec(dummy, dummy.length, 0, ALG);

            jnimeh Jamil Nimeh
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: