[java] How to avoid installing "Unlimited Strength" JCE policy files when deploying an application?

I have an app that uses 256-bit AES encryption which is not supported by Java out of the box. I know to get this to function correctly I install the JCE unlimited strength jars in the security folder. This is fine for me being the developer, I can install them.

My question is since this app will be distributed, end users most likely will not have these policy files installed. Having the end user download these just to make the app function is not an attractive solution.

Is there a way to make my app run without overwriting files on the end user machine? A third party software that can handle it without the policy files installed? Or a way to just reference these policy files from within a JAR?

This question is related to java aes jce policyfiles

The answer is


During installation of your program, just prompt the user and have a DOS Batch script or a Bash shell script download and copy the JCE into the proper system location.

I used to have to do this for a server webservice and instead of a formal installer, I just provided scripts to setup the app before the user could run it. You can make the app un-runnable until they run the setup script. You could also make the app complain that the JCE is missing and then ask to download and restart the app?


For an alternative cryptography library, have a look at Bouncy Castle. It has AES and a lot of added functionality. It's a liberal open source library. You will have to use the lightweight, proprietary Bouncy Castle API for this to work though.


As of JDK 8u102, the posted solutions relying on reflection will no longer work: the field that these solutions set is now final (https://bugs.openjdk.java.net/browse/JDK-8149417).

Looks like it's back to either (a) using Bouncy Castle, or (b) installing the JCE policy files.


Bouncy Castle still requires jars installed as far as I can tell.

I did a little test and it seemed to confirm this:

http://www.bouncycastle.org/wiki/display/JA1/Frequently+Asked+Questions


You could use method

javax.crypto.Cipher.getMaxAllowedKeyLength(String transformation)

to test the available key length, use that and inform the user about what is going on. Something stating that your application is falling back to 128 bit keys due to the policy files not being installed, for example. Security conscious users will install the policy files, others will continue using weaker keys.


For our application, we had a client server architecture and we only allowed decrypting/encrypting data in the server level. Hence the JCE files are only needed there.

We had another problem where we needed to update a security jar on the client machines, through JNLP, it overwrites the libraries in${java.home}/lib/security/ and the JVM on first run.

That made it work.


Here is a modified version of @ntoskrnl's code featuring isRestrictedCryptography check by actual Cipher.getMaxAllowedKeyLength, slf4j logging and support of singleton initialization from application bootstrap like this:

static {
    UnlimitedKeyStrengthJurisdictionPolicy.ensure();
}

This code would correctly stop mangling with reflection when unlimited policy becomes available by default in Java 8u162 as @cranphin's answer predicts.


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.NoSuchAlgorithmException;
import java.security.Permission;
import java.security.PermissionCollection;
import java.util.Map;

// https://stackoverflow.com/questions/1179672/how-to-avoid-installing-unlimited-strength-jce-policy-files-when-deploying-an
public class UnlimitedKeyStrengthJurisdictionPolicy {

    private static final Logger log = LoggerFactory.getLogger(UnlimitedKeyStrengthJurisdictionPolicy.class);

    private static boolean isRestrictedCryptography() throws NoSuchAlgorithmException {
        return Cipher.getMaxAllowedKeyLength("AES/ECB/NoPadding") <= 128;
    }

    private static void removeCryptographyRestrictions() {
        try {
            if (!isRestrictedCryptography()) {
                log.debug("Cryptography restrictions removal not needed");
                return;
            }
            /*
             * Do the following, but with reflection to bypass access checks:
             *
             * JceSecurity.isRestricted = false;
             * JceSecurity.defaultPolicy.perms.clear();
             * JceSecurity.defaultPolicy.add(CryptoAllPermission.INSTANCE);
             */
            Class<?> jceSecurity = Class.forName("javax.crypto.JceSecurity");
            Class<?> cryptoPermissions = Class.forName("javax.crypto.CryptoPermissions");
            Class<?> cryptoAllPermission = Class.forName("javax.crypto.CryptoAllPermission");

            Field isRestrictedField = jceSecurity.getDeclaredField("isRestricted");
            isRestrictedField.setAccessible(true);
            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(isRestrictedField, isRestrictedField.getModifiers() & ~Modifier.FINAL);
            isRestrictedField.set(null, false);

            Field defaultPolicyField = jceSecurity.getDeclaredField("defaultPolicy");
            defaultPolicyField.setAccessible(true);
            PermissionCollection defaultPolicy = (PermissionCollection) defaultPolicyField.get(null);

            Field perms = cryptoPermissions.getDeclaredField("perms");
            perms.setAccessible(true);
            ((Map<?, ?>) perms.get(defaultPolicy)).clear();

            Field instance = cryptoAllPermission.getDeclaredField("INSTANCE");
            instance.setAccessible(true);
            defaultPolicy.add((Permission) instance.get(null));

            log.info("Successfully removed cryptography restrictions");
        } catch (Exception e) {
            log.warn("Failed to remove cryptography restrictions", e);
        }
    }

    static {
        removeCryptographyRestrictions();
    }

    public static void ensure() {
        // just force loading of this class
    }
}

This is now no longer needed for Java 9, nor for any recent release of Java 6, 7, or 8. Finally! :)

Per JDK-8170157, the unlimited cryptographic policy is now enabled by default.

Specific versions from the JIRA issue:

  • Java 9 (10, 11, etc..): Any official release!
  • Java 8u161 or later (Available now)
  • Java 7u171 or later (Only available through 'My Oracle Support')
  • Java 6u181 or later (Only available through 'My Oracle Support')

Note that if for some odd reason the old behavior is needed in Java 9, it can be set using:

Security.setProperty("crypto.policy", "limited");

Here is solution: http://middlesphere-1.blogspot.ru/2014/06/this-code-allows-to-break-limit-if.html

//this code allows to break limit if client jdk/jre has no unlimited policy files for JCE.
//it should be run once. So this static section is always execute during the class loading process.
//this code is useful when working with Bouncycastle library.
static {
    try {
        Field field = Class.forName("javax.crypto.JceSecurity").getDeclaredField("isRestricted");
        field.setAccessible(true);
        field.set(null, java.lang.Boolean.FALSE);
    } catch (Exception ex) {
    }
}

Here's a updated version of ntoskrnl answer. It additionally contains a function to remove the final modifier like Arjan mentioned in the comments.

This version works with JRE 8u111 or newer.

private static void removeCryptographyRestrictions() {
    if (!isRestrictedCryptography()) {
        return;
    }
    try {
        /*
         * Do the following, but with reflection to bypass access checks:
         * 
         * JceSecurity.isRestricted = false; JceSecurity.defaultPolicy.perms.clear();
         * JceSecurity.defaultPolicy.add(CryptoAllPermission.INSTANCE);
         */
        final Class<?> jceSecurity = Class.forName("javax.crypto.JceSecurity");
        final Class<?> cryptoPermissions = Class.forName("javax.crypto.CryptoPermissions");
        final Class<?> cryptoAllPermission = Class.forName("javax.crypto.CryptoAllPermission");

        Field isRestrictedField = jceSecurity.getDeclaredField("isRestricted");
        isRestrictedField.setAccessible(true);
        setFinalStatic(isRestrictedField, true);
        isRestrictedField.set(null, false);

        final Field defaultPolicyField = jceSecurity.getDeclaredField("defaultPolicy");
        defaultPolicyField.setAccessible(true);
        final PermissionCollection defaultPolicy = (PermissionCollection) defaultPolicyField.get(null);

        final Field perms = cryptoPermissions.getDeclaredField("perms");
        perms.setAccessible(true);
        ((Map<?, ?>) perms.get(defaultPolicy)).clear();

        final Field instance = cryptoAllPermission.getDeclaredField("INSTANCE");
        instance.setAccessible(true);
        defaultPolicy.add((Permission) instance.get(null));
    }
    catch (final Exception e) {
        e.printStackTrace();
    }
}

static void setFinalStatic(Field field, Object newValue) throws Exception {
      field.setAccessible(true);

      Field modifiersField = Field.class.getDeclaredField("modifiers");
      modifiersField.setAccessible(true);
      modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

      field.set(null, newValue);
   }

private static boolean isRestrictedCryptography() {
    // This simply matches the Oracle JRE, but not OpenJDK.
    return "Java(TM) SE Runtime Environment".equals(System.getProperty("java.runtime.name"));
}

There are a couple of commonly quoted solutions to this problem. Unfortunately neither of these are entirely satisfactory:

  • Install the unlimited strength policy files. While this is probably the right solution for your development workstation, it quickly becomes a major hassle (if not a roadblock) to have non-technical users install the files on every computer. There is no way to distribute the files with your program; they must be installed in the JRE directory (which may even be read-only due to permissions).
  • Skip the JCE API and use another cryptography library such as Bouncy Castle. This approach requires an extra 1MB library, which may be a significant burden depending on the application. It also feels silly to duplicate functionality included in the standard libraries. Obviously, the API is also completely different from the usual JCE interface. (BC does implement a JCE provider, but that doesn't help because the key strength restrictions are applied before handing over to the implementation.) This solution also won't let you use 256-bit TLS (SSL) cipher suites, because the standard TLS libraries call the JCE internally to determine any restrictions.

But then there's reflection. Is there anything you can't do using reflection?

private static void removeCryptographyRestrictions() {
    if (!isRestrictedCryptography()) {
        logger.fine("Cryptography restrictions removal not needed");
        return;
    }
    try {
        /*
         * Do the following, but with reflection to bypass access checks:
         *
         * JceSecurity.isRestricted = false;
         * JceSecurity.defaultPolicy.perms.clear();
         * JceSecurity.defaultPolicy.add(CryptoAllPermission.INSTANCE);
         */
        final Class<?> jceSecurity = Class.forName("javax.crypto.JceSecurity");
        final Class<?> cryptoPermissions = Class.forName("javax.crypto.CryptoPermissions");
        final Class<?> cryptoAllPermission = Class.forName("javax.crypto.CryptoAllPermission");

        final Field isRestrictedField = jceSecurity.getDeclaredField("isRestricted");
        isRestrictedField.setAccessible(true);
        final Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(isRestrictedField, isRestrictedField.getModifiers() & ~Modifier.FINAL);
        isRestrictedField.set(null, false);

        final Field defaultPolicyField = jceSecurity.getDeclaredField("defaultPolicy");
        defaultPolicyField.setAccessible(true);
        final PermissionCollection defaultPolicy = (PermissionCollection) defaultPolicyField.get(null);

        final Field perms = cryptoPermissions.getDeclaredField("perms");
        perms.setAccessible(true);
        ((Map<?, ?>) perms.get(defaultPolicy)).clear();

        final Field instance = cryptoAllPermission.getDeclaredField("INSTANCE");
        instance.setAccessible(true);
        defaultPolicy.add((Permission) instance.get(null));

        logger.fine("Successfully removed cryptography restrictions");
    } catch (final Exception e) {
        logger.log(Level.WARNING, "Failed to remove cryptography restrictions", e);
    }
}

private static boolean isRestrictedCryptography() {
    // This matches Oracle Java 7 and 8, but not Java 9 or OpenJDK.
    final String name = System.getProperty("java.runtime.name");
    final String ver = System.getProperty("java.version");
    return name != null && name.equals("Java(TM) SE Runtime Environment")
            && ver != null && (ver.startsWith("1.7") || ver.startsWith("1.8"));
}

Simply call removeCryptographyRestrictions() from a static initializer or such before performing any cryptographic operations.

The JceSecurity.isRestricted = false part is all that is needed to use 256-bit ciphers directly; however, without the two other operations, Cipher.getMaxAllowedKeyLength() will still keep reporting 128, and 256-bit TLS cipher suites won't work.

This code works on Oracle Java 7 and 8, and automatically skips the process on Java 9 and OpenJDK where it's not needed. Being an ugly hack after all, it likely doesn't work on other vendors' VMs.

It also doesn't work on Oracle Java 6, because the private JCE classes are obfuscated there. The obfuscation does not change from version to version though, so it is still technically possible to support Java 6.


Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to aes

How to fix Invalid AES key length? AES Encrypt and Decrypt How to create a secure random AES key in Java? Initial bytes incorrect after Java AES/CBC decryption Example of AES using Crypto++ Java AES encryption and decryption How to do encryption using AES in Openssl C# Example of AES256 encryption using System.Security.Cryptography.Aes Image encryption/decryption using AES256 symmetric block ciphers Comparison of DES, Triple DES, AES, blowfish encryption for data

Examples related to jce

How to create a secure random AES key in Java? Trust Store vs Key Store - creating with keytool Why java.security.NoSuchProviderException No such provider: BC? Hash String via SHA-256 in Java How to avoid installing "Unlimited Strength" JCE policy files when deploying an application?

Examples related to policyfiles

How to avoid installing "Unlimited Strength" JCE policy files when deploying an application?