8

I have a spring TextEncryptor defined like this

<bean id="textEncryptor" class="org.springframework.security.crypto.encrypt.Encryptors"
                                                  factory-method="text">
        <constructor-arg value="${security.encryptPassword}" />
        <constructor-arg value="${security.encryptSalt}" />
</bean>

Which is fed these properties

security.encryptPassword=47582920264f212c566d5e5a6d
security.encryptSalt=39783e315e6a207e733d6f4141

Which works fine on my local environment. When I deploy to Heroku I get

java.lang.IllegalArgumentException: Unable to initialize due to invalid secret key
at org.springframework.security.crypto.encrypt.CipherUtils.initCipher(CipherUtils.java:110)
at org.springframework.security.crypto.encrypt.AesBytesEncryptor.encrypt(AesBytesEncryptor.java:65)
at org.springframework.security.crypto.encrypt.HexEncodingTextEncryptor.encrypt(HexEncodingTextEncryptor.java:36)
...
Caused by: java.security.InvalidKeyException: Illegal key size
at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:972)
at javax.crypto.Cipher.implInit(Cipher.java:738)
at javax.crypto.Cipher.chooseProvider(Cipher.java:797)
at javax.crypto.Cipher.init(Cipher.java:1276)
at javax.crypto.Cipher.init(Cipher.java:1215)
at org.springframework.security.crypto.encrypt.CipherUtils.initCipher(CipherUtils.java:105)
... 53 more

So I tried some smaller keys but I always get the same problem. What is the correct key size to use on Heroku?

Ollie Edwards
  • 14,042
  • 7
  • 28
  • 36

3 Answers3

13

My answer is a bit late but I wrote it to help anyone in need. By default, spring security uses a 256-bit key for encryption. This is not permitted by the JDK by default, which supported up to 128-bit keys only.

To solve this, you need need to download the local_policy.jar & US_export_policy.jar jars from oracle (Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 7 Download) and replace them in jdk_path/jre/lib/security/. Make sure you restart the application server for the changes to take effect.

On a separate note, I wouldn't place the secret key in a properties file. Instead I recommend you put it in a key store. If you need help with that let me know.

UdayKiran Pulipati
  • 6,579
  • 7
  • 67
  • 92
Ayman
  • 1,682
  • 15
  • 17
  • Yes that is the correct solution for a local install. The point is on a remote managed platform like heroku we don't have control over the JDK. – Ollie Edwards Jul 17 '13 at 09:11
  • I just amazing - why these files are not bundled with java. – msangel Aug 06 '13 at 13:55
  • 1
    @msangel I'd say that its a US Crypto export restriction. I'm surprised we (those who are non-US citizens) have such free access to them). – HankCa Nov 28 '13 at 00:19
  • Are you able to outline the advantages of a keystore? Would that require also storing the password to the keystore somewhere in plain text? – John Deverall Jan 24 '15 at 13:11
  • 1
    Hi John, the whole concept is not having the password in plain text format in a properties / XML config file. We got this marked as a "Low Priority" issue by one security auditor. – Ayman Feb 02 '15 at 19:30
  • 2
    This link is for Java 8 http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html – Sanghyun Lee Sep 09 '15 at 03:30
  • This also worked for me after placing the files under the JRE path of "maven --version". – Marcello DeSales Jul 26 '16 at 08:15
7

So I think I've concluded Heroku just plain doesn't support 256 bit AEP which is what the stock TextEncoders in spring-security use.

Instead I've used the BasicTextEncryptor from the Java Simplified Encryption library as an alternative backend and implemented the TextEncryptor interface.

It's less secure but it works. It doesn't provide a salting mechanism, though I think there are provisions for that elsewhere in the library.

If anyone has any ideas how to get the stock encryptors working on heroku then that would still be preferable I think.

UdayKiran Pulipati
  • 6,579
  • 7
  • 67
  • 92
Ollie Edwards
  • 14,042
  • 7
  • 28
  • 36
0

You can also do the following. Though this seems to have stopped working on the latest builds of Java 8.

    Field field = Class.forName("javax.crypto.JceSecurity").getDeclaredField("isRestricted");
    if (Boolean.TRUE.equals(field.get(null))) {
        if (Modifier.isFinal(field.getModifiers())) {
            Field modifiers = Field.class.getDeclaredField("modifiers");
            modifiers.setAccessible(true);
            modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        }
        field.setAccessible(true);
        field.setBoolean(null, false); // isRestricted = false;
        field.setAccessible(false);
    }
    textEncryptor = Encryptors.text(key, salt);
Jose Martinez
  • 11,452
  • 7
  • 53
  • 68