Java: Patching client side security policy from applet for AES256
Asked Answered
M

2

5

I require AES256 encryption/decryption in a commercial web application. Currently everything is good with a key size of 128. This is not satisfactory cryptographically so my problem is how best to get round this issue without requiring the user to install anything manually.

I have the unlimited jurisdiction jar files from Oracle but I have no idea if replacing these in the user's JRE/lib/security directory will be compatible with older versions. Obviously I don't want to corrupt the user's JRE. Also I have write permission to my JRE security directory but I assume some user's will not have these privileges.

Is there a simple way around this issue, or am I stuck with either weak encryption or a potentially problematic step for users?


Update for "unrestricting" javax.crypto.JceSecurity

@ntoskml You are correct. getMaxAllowedKeyLength still returns the limited key size but the encryption succeeds with key size == 256 :). I will update my test method and set the key size if strong encryption is available. Thanks

>>> from javax.crypto import Cipher
>>> Cipher.getMaxAllowedKeyLength("AES")
128
>>> from java.lang import Class
>>> c = Class.forName("javax.crypto.JceSecurity")
>>> isRestricted = c.getDeclaredField("isRestricted")
>>> isRestricted.setAccessible(True)
>>> isRestricted.set(None, False)
>>> isRestricted.get(None)
False
>>> Cipher.getMaxAllowedKeyLength("AES")
128
>>> from javax.crypto import KeyGenerator
>>> kge = KeyGenerator.getInstance("AES")
>>> kge.init(256)
>>> aesKey = kgen.generateKey()
>>> c2 = Cipher.getInstance("AES")
>>> c2.init(Cipher.ENCRYPT_MODE, aesKey)
>>> c2.doFinal("test")
array('b', [-81, 99, -61, -51, 93, -42, -68, -28, 107, 59, -109, -98, -25, 127, 37, 23])

And the test case after restarting Jython console

>>> # Reflection as above
>>> isRestricted.get(None)
True
>>> kge.init(256)
>>> aesKey = kge.generateKey()
>>> c2.init(Cipher.ENCRYPT_MODE, aesKey)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
        at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1011)
        at javax.crypto.Cipher.implInit(Cipher.java:786)
        at javax.crypto.Cipher.chooseProvider(Cipher.java:849)
        at javax.crypto.Cipher.init(Cipher.java:1213)
        at javax.crypto.Cipher.init(Cipher.java:1153)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)

java.security.InvalidKeyException: java.security.InvalidKeyException: Illegal key size or default parameters

Bingo :) Thanks for sharing @ntoskml

Maddeu answered 26/8, 2013 at 0:54 Comment(5)
Please don't edit the question this way - currently it is a bit hard to read for people looking for a solution. I would also like to know the restrictions on using this answer. Normally applets do not allow you to use reflections this way - at least not when run in the browser.Tattoo
@owlstead Where should I put this?Maddeu
This method works in applet running Windows 8 64 bit Java(TM) SE Runtime Environment 1.7.0_21Maddeu
Oh, that's cool. Wouldn't have expected that to work because of applet restrictions.Tattoo
possible duplicate of "Unlimited Strength" JCE Policy FilesLiebman
L
5

EDIT: Here's an updated answer to this question: How to avoid installing "Unlimited Strength" JCE policy files when deploying an application?


It is possible to disable the key size restrictions simply by using a few lines of reflection. We use this method in our program which needs access to 256-bit cryptography for interoperability purposes.

private static void removeCryptographyRestrictions() {
    if (!isRestrictedCryptography()) {
        return;
    }
    try {
        java.lang.reflect.Field isRestricted;
        try {
            final Class<?> c = Class.forName("javax.crypto.JceSecurity");
            isRestricted = c.getDeclaredField("isRestricted");
        } catch (final ClassNotFoundException e) {
            try {
                // Java 6 has obfuscated JCE classes
                final Class<?> c = Class.forName("javax.crypto.SunJCE_b");
                isRestricted = c.getDeclaredField("g");
            } catch (final ClassNotFoundException e2) {
                throw e;
            }
        }
        isRestricted.setAccessible(true);
        isRestricted.set(null, false);
    } catch (final Throwable e) {
        logger.log(Level.WARNING,
                "Failed to remove cryptography restrictions", e);
    }
}

private static boolean isRestrictedCryptography() {
    return "Java(TM) SE Runtime Environment"
            .equals(System.getProperty("java.runtime.name"));
}

However, our program is not an applet, and I am not sure whether applets have access to the reflection API.

The question about legality also remains. There is a reason for that limit. Consult a lawyer if you are concerned.

If possible, try to keep it to 128-bit keys. Even when taking Moore's law into consideration, breaking 128-bit AES would take billions upon billions of years. Longer keys offer no benefit in the real world – particularly when the keys are derived from passwords, which don't have anywhere near 256 bits of entropy anyway.

Liebman answered 26/8, 2013 at 5:9 Comment(7)
Champion. Will try it out tomorrow. There is hope yet ;)Maddeu
@ntoskml No luck here. Sets the class variable on JceSecurity but fails to allow keysize >= 128. Java version: SE 1.7.0_21Maddeu
@Maddeu That is odd, because it works for us in all versions of Java 6 and 7 we have tested. We haven't heard any reports from users either. In fact, even Java 8 still has the same class and field. Did you invoke this method before loading any crypto classes? Try invoking it from a static initializer to make sure. Other than that, it sounds like a problem with applets. Maybe some security policy or classloader trickery? Please try it in a non-applet environment to rule out other issues.Liebman
@Maddeu If you can't even use 128-bit keys, there are other problems with your setup (unless the ">=" was a typo of course).Liebman
@ntoskml keysize > 128 :\ I'm testing your code from a main method not in an applet context. Checking using your method (java.runtime.name) as well as my own Cipher.getMaxAllowedKeyLength("AES"). Key size is always 128 and runtime name is Java(TM) SE Runtime EnvironmentMaddeu
@ntoskml i have added some Jython to my question showing the problem (same issue in Java main)Maddeu
@Maddeu I'm not sure if this is supposed to have any effect on the result of Cipher.getMaxAllowedKeyLength("AES"). Just try performing AES operations with 256-bit keys and see if it works.Liebman
T
2

You are either stuck with the weak encryption or a potentially problematic step for users if you stick to the SunJCE.

There is obviously no problem importing an AES library, there is just a problem using it using an instance of Cipher. If you have a specific piece of software that does not depend on JCA, you can for instance rewrite it to use the lightweight crypto API of Bouncy Castle.

Note that many other parts of the Bouncy API themselves depend on the JCE. The lightweight API is also trickier to use and less documented/tested than the SunJCE.

The Bouncy Castle lightweight API is pretty large as well. It contains a lot of functionality that you won't need. So it is probably too large for your applet. If it is I would advice you to create a new library that only contains the specific classes that you need from Bouncy Castle. The Bouncy Castle is fortunately very liberally licensed. As long as you keep the copyright statements etc. in place, you can easily split it off.

Tattoo answered 26/8, 2013 at 1:2 Comment(5)
Does the BC solution involve much bloat. Being an applet is a bit restrictive. I have tried to avoid it thus far.Maddeu
Would that be the "JCE with provider and lightweight API" at bouncycastle latest releases you mean for this functionality? That is around 7.7 meg as a zip. The "Lightweight API" beside it is a 6.6 meg zip. I am just musing about how much extra bytes it will mean for the applet user.. BTW - as to the problem (well, closer).. What does this applet do exactly? Why the strong(?) encryption?Squeak
I want to encrypt and store a PKCS#12 key store password between sessions in the browser context. The key store access is used to sign uploads and decrypt tokens downloaded (separate functions). Otherwise the user may need to enter their password repeatedly.Maddeu
@Maddeu that's a bit heavy for an applet. PKCS#12 requires parsing of ASN.1 structures. As for the AES in the original question, it's probably best to simply strip out the AES functionality. The bouncy license is not very restrictive. In principle the answer goes for any AES implementation, as long as it does not use Cipher. Sorry, forgot about any size constraints.Tattoo
@owlstead PKCS#12 is sorted. Just need a way to securely cache the password client side. Thanks for that. Striping the BC AES is an optionMaddeu

© 2022 - 2024 — McMap. All rights reserved.