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

Use SunJCE Mac in SecretKeyFactory PBKDF2 implementation

    XMLWordPrintable

    Details

    • Subcomponent:
    • Introduced In Version:
      9
    • Resolved In Build:
      b13
    • CPU:
      x86_64
    • OS:
      windows_7

      Description

      ADDITIONAL SYSTEM INFORMATION :
      generic / generic / java version "11.0.2" 2019-01-15 LTS
      Java(TM) SE Runtime Environment 18.9 (build 11.0.2+9-LTS)
      Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.2+9-LTS, mixed mode)

      A DESCRIPTION OF THE PROBLEM :
      A call to SecretKeyFactory getInstance( algo_, provider_ ), ignores the provider argument (in this example "SunJCE") and always uses the first provider in the provider list when calculating HMAC.

      When adding third party crypto providers, such as bc-fips-1.0.1.jar as first provider and invoking the code

      PBEKeySpec spec = new PBEKeySpec( ""Test#1234".toCharArray(), "[B@2054babb".getBytes(), 10000, 16 * 8 );
      SecretKeyFactory skf = SecretKeyFactory.getInstance( "PBKDF2WithHmacSHA1", "SunJCE" );
      skf.generateSecret( spec ).getEncoded();

      leads to:

      org.bouncycastle.crypto.IllegalKeyException: Key size for HMAC must be at least 112 bits in approved mode: SHA-1/HMAC
      at org.bouncycastle.crypto.fips.FipsSHS$MACOperatorFactory.createMAC(Unknown Source)
      at org.bouncycastle.crypto.fips.FipsSHS$MACOperatorFactory.createMAC(Unknown Source)
      at org.bouncycastle.crypto.fips.FipsMACOperatorFactory.createOutputMACCalculator(Unknown Source)
      at org.bouncycastle.crypto.fips.FipsMACOperatorFactory.createOutputMACCalculator(Unknown Source)
      at org.bouncycastle.jcajce.provider.BaseHMac.engineInit(Unknown Source)
      at java.base/javax.crypto.Mac.init(Mac.java:433)
      at java.base/com.sun.crypto.provider.PBKDF2KeyImpl.deriveKey(PBKDF2KeyImpl.java:182)
      at java.base/com.sun.crypto.provider.PBKDF2KeyImpl.<init>(PBKDF2KeyImpl.java:122)
      at java.base/com.sun.crypto.provider.PBKDF2Core.engineGenerateSecret(PBKDF2Core.java:69)
      at java.base/javax.crypto.SecretKeyFactory.generateSecret(SecretKeyFactory.java:338)

      This worked earlier with Java 8 Update 192

      REGRESSION : Last worked in version 8u192

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Add BC FIPS Provider at position 1 and set the FIPS approved mode to true. (Code attached)
      2. Generate Secret using "SunJCE" provider as shown below. (Code attached)

      PBEKeySpec spec = new PBEKeySpec( ""Test#1234".toCharArray(), "[B@2054babb".getBytes(), 10000, 16 * 8 );
      SecretKeyFactory skf = SecretKeyFactory.getInstance( "PBKDF2WithHmacSHA1", "SunJCE" );
      skf.generateSecret( spec ).getEncoded();

      Compile and run the SecretKeyFactoryUsingSunJCETest class with bc-fips-1.0.1.jar added to the classpath

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Java SecurityProvider list:

      Provider at position = 1 has name = SUN
      Provider at position = 2 has name = SunRsaSign
      Provider at position = 3 has name = SunEC
      Provider at position = 4 has name = SunJSSE
      Provider at position = 5 has name = SunJCE
      Provider at position = 6 has name = SunJGSS
      Provider at position = 7 has name = SunSASL
      Provider at position = 8 has name = XMLDSig
      Provider at position = 9 has name = SunPCSC
      Provider at position = 10 has name = SunMSCAPI

      Added Provider to Position 1: BCFIPS

      BouncyCastle FIPStatus: true
      BouncyCastle FIPS Approved Mode: true

      Java SecurityProvider list:

      Provider at position = 1 has name = BCFIPS
      Provider at position = 2 has name = SUN
      Provider at position = 3 has name = SunRsaSign
      Provider at position = 4 has name = SunEC
      Provider at position = 5 has name = SunJSSE
      Provider at position = 6 has name = SunJCE
      Provider at position = 7 has name = SunJGSS
      Provider at position = 8 has name = SunSASL
      Provider at position = 9 has name = XMLDSig
      Provider at position = 10 has name = SunPCSC
      Provider at position = 11 has name = SunMSCAPI
      Using JCE_PROVIDER for SecretKeyFactory ## = SunJCE
      Secret Code: [B@4c1bdcc2

      Process finished with exit code 0
      ACTUAL -
      Java SecurityProvider list:

      Provider at position = 1 has name = SUN
      Provider at position = 2 has name = SunRsaSign
      Provider at position = 3 has name = SunEC
      Provider at position = 4 has name = SunJSSE
      Provider at position = 5 has name = SunJCE
      Provider at position = 6 has name = SunJGSS
      Provider at position = 7 has name = SunSASL
      Provider at position = 8 has name = XMLDSig
      Provider at position = 9 has name = SunPCSC
      Provider at position = 10 has name = SunMSCAPI

      Added Provider to Position 1: BCFIPS

      BouncyCastle FIPStatus: true
      BouncyCastle FIPS Approved Mode: true

      Java SecurityProvider list:

      Provider at position = 1 has name = BCFIPS
      Provider at position = 2 has name = SUN
      Provider at position = 3 has name = SunRsaSign
      Provider at position = 4 has name = SunEC
      Provider at position = 5 has name = SunJSSE
      Provider at position = 6 has name = SunJCE
      Provider at position = 7 has name = SunJGSS
      Provider at position = 8 has name = SunSASL
      Provider at position = 9 has name = XMLDSig
      Provider at position = 10 has name = SunPCSC
      Provider at position = 11 has name = SunMSCAPI
      Using JCE_PROVIDER for SecretKeyFactory ## = SunJCE
      org.bouncycastle.crypto.IllegalKeyException: Key size for HMAC must be at least 112 bits in approved mode: SHA-1/HMAC
      at org.bouncycastle.crypto.fips.FipsSHS$MACOperatorFactory.createMAC(Unknown Source)
      at org.bouncycastle.crypto.fips.FipsSHS$MACOperatorFactory.createMAC(Unknown Source)
      at org.bouncycastle.crypto.fips.FipsMACOperatorFactory.createOutputMACCalculator(Unknown Source)
      at org.bouncycastle.crypto.fips.FipsMACOperatorFactory.createOutputMACCalculator(Unknown Source)
      at org.bouncycastle.jcajce.provider.BaseHMac.engineInit(Unknown Source)
      at java.base/javax.crypto.Mac.init(Mac.java:433)
      at java.base/com.sun.crypto.provider.PBKDF2KeyImpl.deriveKey(PBKDF2KeyImpl.java:182)
      at java.base/com.sun.crypto.provider.PBKDF2KeyImpl.<init>(PBKDF2KeyImpl.java:122)
      at java.base/com.sun.crypto.provider.PBKDF2Core.engineGenerateSecret(PBKDF2Core.java:69)
      at java.base/javax.crypto.SecretKeyFactory.generateSecret(SecretKeyFactory.java:338)
      at PBKDF2HmacSHA1Test.pbkdf2Encryption(PBKDF2HmacSHA1Test.java:72)
      at PBKDF2HmacSHA1Test.generateSecret(PBKDF2HmacSHA1Test.java:55)
      at PBKDF2HmacSHA1Test.generateSecretCodeUsingBouncyCastle(PBKDF2HmacSHA1Test.java:40)
      at PBKDF2HmacSHA1Test.main(PBKDF2HmacSHA1Test.java:27)
      Exception in thread "main" org.bouncycastle.crypto.IllegalKeyException: Key size for HMAC must be at least 112 bits in approved mode: SHA-1/HMAC
      at org.bouncycastle.crypto.fips.FipsSHS$MACOperatorFactory.createMAC(Unknown Source)
      at org.bouncycastle.crypto.fips.FipsSHS$MACOperatorFactory.createMAC(Unknown Source)
      at org.bouncycastle.crypto.fips.FipsMACOperatorFactory.createOutputMACCalculator(Unknown Source)
      at org.bouncycastle.crypto.fips.FipsMACOperatorFactory.createOutputMACCalculator(Unknown Source)
      at org.bouncycastle.jcajce.provider.BaseHMac.engineInit(Unknown Source)
      at java.base/javax.crypto.Mac.init(Mac.java:433)
      at java.base/com.sun.crypto.provider.PBKDF2KeyImpl.deriveKey(PBKDF2KeyImpl.java:182)
      at java.base/com.sun.crypto.provider.PBKDF2KeyImpl.<init>(PBKDF2KeyImpl.java:122)
      at java.base/com.sun.crypto.provider.PBKDF2Core.engineGenerateSecret(PBKDF2Core.java:69)
      at java.base/javax.crypto.SecretKeyFactory.generateSecret(SecretKeyFactory.java:338)
      at PBKDF2HmacSHA1Test.pbkdf2Encryption(PBKDF2HmacSHA1Test.java:72)
      at PBKDF2HmacSHA1Test.generateSecret(PBKDF2HmacSHA1Test.java:55)
      at PBKDF2HmacSHA1Test.generateSecretCodeUsingBouncyCastle(PBKDF2HmacSHA1Test.java:40)
      at PBKDF2HmacSHA1Test.main(PBKDF2HmacSHA1Test.java:27)

      Process finished with exit code 1

      ---------- BEGIN SOURCE ----------
      import javax.crypto.SecretKeyFactory;
      import javax.crypto.spec.PBEKeySpec;
      import java.security.NoSuchAlgorithmException;
      import java.security.NoSuchProviderException;
      import java.security.Provider;
      import java.security.Security;
      import java.security.spec.InvalidKeySpecException;

      public class SecretKeyFactoryUsingSunJCETest
      {
        private static final String PBKDF2_SHA_ALGORITHM = "PBKDF2WithHmacSHA1";

        public static final String SUN_JCE_PROVIDER = "SunJCE";
        public static final String BOUNCYCASTLE_JCE_PROVIDER = "BCFIPS";

        public static final int HASH_BYTE_SIZE = 16;
        public static final int PBKDF2_ITERATIONS = 10000;

        public static final String PASSWORD = "Test#1234";
        public static final String SALT = "[B@2054babb";

        public static void main( String[] args_ ) throws Exception
        {
          byte[] secretCode = null;

          secretCode = generateSecretCode();

          System.out.println("Secret Code: " + secretCode);
        }

        private static byte[] generateSecretCode() throws InvalidKeySpecException, NoSuchAlgorithmException
        {
          byte[] secretCode = null;
          printProviders();
          addBouncyCastleProvider( true ); // Add BouncyCastle provider to the security providers list
          printProviders();
          secretCode = generateSecret( PASSWORD, SALT, SUN_JCE_PROVIDER );
          removeBouncyCastleProvider();
          return secretCode;
        }

        public static byte[] generateSecret( String data_, String salt_, String provider_ )
          throws InvalidKeySpecException, NoSuchAlgorithmException
        {
          // Hash the password
          byte[] hash = new byte[0];
          try
          {
            hash = pbkdf2Encryption( data_.toCharArray(), salt_.getBytes(), PBKDF2_ITERATIONS, HASH_BYTE_SIZE, provider_ );
          }
          catch( Exception e )
          {
            e.printStackTrace();
            throw e;
          }

          return hash;
        }

        private static byte[] pbkdf2Encryption( char[] password_, byte[] salt_, int iterations_, int bytes_,
                                                String provider_ )
          throws NoSuchAlgorithmException, InvalidKeySpecException, SecurityException
        {
          PBEKeySpec spec = new PBEKeySpec( password_, salt_, iterations_, bytes_ * 8 );
          SecretKeyFactory skf = getSecretKeyFactoryInstance( PBKDF2_SHA_ALGORITHM, provider_ );
          return skf.generateSecret( spec ).getEncoded();
        }

        public static SecretKeyFactory getSecretKeyFactoryInstance( String algorithm_, String provider_ )
          throws SecurityException
        {
          SecretKeyFactory secretKeyFactory = null;
          try
          {
            secretKeyFactory = SecretKeyFactory.getInstance( algorithm_, provider_ );
          }
          catch( NoSuchAlgorithmException | NoSuchProviderException e )
          {
            e.printStackTrace();
          }

          System.out.println( "Using JCE_PROVIDER for SecretKeyFactory ## = " + secretKeyFactory.getProvider().getName() );

          return secretKeyFactory;
        }

        public static void addBouncyCastleProvider( boolean fipsMode_ )
        {
          Provider bouncyCastleFipsProvider = new org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider();

          addProvider( BOUNCYCASTLE_JCE_PROVIDER, bouncyCastleFipsProvider );

          // Set FIPS Approved Mode ON - BouncyCastle
          org.bouncycastle.crypto.CryptoServicesRegistrar.setApprovedOnlyMode( fipsMode_ );

          System.out.println( "BouncyCastle FIPStatus: " +
                              org.bouncycastle.crypto.fips.FipsStatus.isReady() );
          System.out.println( "BouncyCastle FIPS Approved Mode: " +
                              org.bouncycastle.crypto.CryptoServicesRegistrar.isInApprovedOnlyMode() );
        }

        private static void addProvider( String providerName_, Provider provider_ )
        {
          try
          {
            int index = getProviderIndex( providerName_ );

            // If the provider is already present first remove it.
            if( (index != -1) )
            {
              Security.removeProvider( providerName_ );
            }
            Security.insertProviderAt( provider_, 1 );
          }
          catch( Exception e )
          {
            throw new SecurityException( "Could not add Security Provider " + providerName_, e );
          }

          System.out.println("\nAdded Provider to Position 1: " + providerName_ + "\n");
        }

        public static void removeBouncyCastleProvider()
          throws SecurityException
        {
          removeProvider( BOUNCYCASTLE_JCE_PROVIDER );
        }

        private static void removeProvider( String providerName_ )
        {
          try
          {
            Security.removeProvider( providerName_ );
          }
          catch( Exception e )
          {
            throw new SecurityException( "Could not add Crypto-J JCE Provider.", e );
          }
        }

        public static void printProviders()
        {
          System.out.println( "\nJava SecurityProvider list:\n" );
          Provider[] providers_ = Security.getProviders();
          int i = 1;
          for( Provider provider : providers_ )
          {
            System.out.println( "Provider at position = " + i + " has name = " + provider.getName() );
            i++;
          }
        }

        public static int getProviderIndex( String providerName_ )
        {
          int providerIndex = 1;
          if( providerName_ == null )
          {
            return -1;
          }
          Provider[] providers_ = Security.getProviders();
          for( Provider provider : providers_ )
          {
            if( providerName_.equalsIgnoreCase( provider.getName() ) )
            {
              return providerIndex;
            }
            providerIndex++;
          }
          return -1;
        }
      }
      ---------- END SOURCE ----------

      FREQUENCY : always


        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                jnimeh Jamil Nimeh
                Reporter:
                webbuggrp Webbug Group
              • Votes:
                0 Vote for this issue
                Watchers:
                3 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: