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

Cipher.init(int, key) does not use highest priority provider for random bytes

XMLWordPrintable

    • b15
    • generic
    • generic
    • Not verified

        A DESCRIPTION OF THE PROBLEM :
        The Javadoc for Cipher.init(int opmode, Key key) says the following:
        "If this cipher (including its underlying feedback or padding scheme) requires any random bytes (e.g., for parameter generation), it will get them using the SecureRandom implementation of the highest-priority installed provider as the source of randomness."

        However the implementation of this method does this (I checked Oracle JDK v1.8 and Zulu JDK 11.0.9 based on OpenJDK):

            public final void init(int opmode, Key key) throws InvalidKeyException {
                init(opmode, key, JceSecurity.RANDOM);
            }

        And this is JceSecurity.RANDOM:
            static final SecureRandom RANDOM = new SecureRandom();

        As a result, it doesn't matter what the highest priority provider is at the moment this method is called. It will always pick a previously created instance that is associated with whatever provider was highest priority at the time that it was created.


        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        I tested this using the following two Bouncy Castle providers but it can happen with any Provider:
        * https://mvnrepository.com/artifact/org.bouncycastle/bc-fips
        * https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on

        In the source code for a test case I'll use the former.

        Steps:
        1. Instantiate a Cipher object and initialize it using Cipher.init(int, key).
        2. Add a new provider at highest priority, one that supports SecureRandom.
        3. Instantiate a Cipher object and initialize it using Cipher.init(int, key).


        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        The call in step 3 should create a SecureRandom instance that uses the new provider.

        The implementation should be the following or (if the intent is to cache the instance) it should check if the an instance is cached for the current highest priority provider of SecureRandom:
            public final void init(int opmode, Key key) throws InvalidKeyException {
                init(opmode, key, new SecureRandom());
            }

        ACTUAL -
        The new provider is not used. If you use the FIPS-compliant BC Provider in strict mode it causes an exception, which is a good way to test this at runtime. See the source code for an executable test case.


        ---------- BEGIN SOURCE ----------
         void testCipherInitSecureRandomBug() throws Exception {
            CryptoServicesRegistrar.setApprovedOnlyMode(true);
            BouncyCastleFipsProvider bcProvider = new BouncyCastleFipsProvider();

            // ensure that the highest priority provider for SecureRandom is SUN
            System.out.println(new SecureRandom().getProvider().getName());
            assert(new SecureRandom().getProvider().getName().equals("SUN"));

            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(new byte[32], "AES")); // succeeds

            Security.insertProviderAt(bcProvider, 1);

            // ensure that the highest priority provider for SecureRandom is BC
            assert(new SecureRandom().getProvider().getName().startsWith("BC"));

            cipher = Cipher.getInstance("AES/GCM/NoPadding");
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(new byte[32], "AES")); // fails
          }

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

        CUSTOMER SUBMITTED WORKAROUND :
        Call an init() method that accepts an explicit SecureRandom argument.

        Unfortunately this workaround may not work for applications relying on libraries that make the Cipher.init() call.


        FREQUENCY : always


              valeriep Valerie Peng
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              7 Start watching this issue

                Created:
                Updated:
                Resolved: