1

I am getting Invalid Key Size error when I try to use 256 bits key in AES encryption. I know I have to use JCE unlimited policy. I am using Jre1.8.0_181. So, I have set crypto.policy=unlimited in java.security file. I have also checked that I am using the correct jvm.

Even I am getting "unlimited" value whenever I use this code.

String value = System.getProperties("crypto.policy"); //getting value = "unlimited"

But after this, I am getting key size to 128 bits.

Cipher.getMaxAllowedKeyLength("AES");

I have followed this code from the following site: https://howtodoinjava.com/java/java-security/aes-256-encryption-decryption/

Code Added

  public static void main(String[] args) {
    String originalString = "howtodoinjava.com";
 
    String encryptedString = AES256.encrypt(originalString);
    String decryptedString = AES256.decrypt(encryptedString);
 
    System.out.println(originalString);
    System.out.println(encryptedString);
    System.out.println(decryptedString);
  }
}
public class AES256 {
  private static final String SECRET_KEY = "my_super_secret_key_ho_ho_ho";
  private static final String SALT = "ssshhhhhhhhhhh!!!!";
 
  public static String decrypt(String strToDecrypt) {
    try {
      byte[] iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
      IvParameterSpec ivspec = new IvParameterSpec(iv);
 
      SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
      KeySpec spec = new PBEKeySpec(SECRET_KEY.toCharArray(), SALT.getBytes(), 65536, 256);
      SecretKey tmp = factory.generateSecret(spec);
      SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");
 
      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
      cipher.init(Cipher.DECRYPT_MODE, secretKey, ivspec);
      return new String(cipher.doFinal(Base64.getDecoder().decode(strToDecrypt)));
    } catch (Exception e) {
      System.out.println("Error while decrypting: " + e.toString());
    }
    return null;
  }
public static String encrypt(String strToEncrypt) {
    try {
      byte[] iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
      IvParameterSpec ivspec = new IvParameterSpec(iv);
 
      SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
      KeySpec spec = new PBEKeySpec(SECRET_KEY.toCharArray(), SALT.getBytes(), 65536, 256);
      SecretKey tmp = factory.generateSecret(spec);
      SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");
 
      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
      cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivspec);
      return Base64.getEncoder()
          .encodeToString(cipher.doFinal(strToEncrypt.getBytes(StandardCharsets.UTF_8)));
    } catch (Exception e) {
      System.out.println("Error while encrypting: " + e.toString());
    }
    return null;
  }

}
8
  • 1
    Java 8 doesn't support property crypto.policy=unlimited. Property 'crypto.policy' has been added in Java 9, where JCE unimited strength is enabled by default, it can be used in form: 'crypto.policy=limited' to disable it. Commented Jul 12, 2021 at 12:38
  • 1
    Since Java 1.8.0_161 unlimited strength policy is active by default. You don't have to modify anything. Just use AES 256 and you will be fine. Commented Jul 12, 2021 at 12:49
  • If it fails you are using not the Java version you mentioned. Commented Jul 12, 2021 at 12:53
  • I have tried AES 256...But got Invalid Key Size Error. I have followed this link: howtodoinjava.com/java/java-security/… Commented Jul 12, 2021 at 12:53
  • I've got the above mentioned jre version when I have tried the commnad: java -version in cmd Commented Jul 12, 2021 at 12:55

2 Answers 2

1

Thanks for editing your post. Your given code runs successfully on my system and seems to be correct.

My simple program will test for something that is called "unlimited crypto policies". Due to US export restrictions, the US companies were not allowed to ship their programs with an unlimited key format. You are using AES with a 32 bytes long key, so it is called AES-256 (32 bytes * 8 bit = 256) but the government allowed only 16 bytes long keys ("AES 128").

My program runs the test depending on the Java version that is in use. For an easier test, I set up a JFiddle-link where you can test the program directly and for convinience change the Java version. The JFiddle is available under this link: https://www.jdoodle.com/a/2nZe

When running the test the Java version is JDK 11.0.4, but you can change (please scroll down) to JDK 1.8.0_66.

output Java 11:

Check for unlimited crypto policies
restricted cryptography: false Notice: 'false' means unlimited policies
Security properties: unlimited
Max AES key length = 2147483647

output for Java 1.8.0_66:

restricted cryptography: true Notice: 'false' means unlimited policies
Security properties: null
Max AES key length = 128

To enable the unlimited policy for older Java's like 1.8.0_66 your clients have to load two small files from Oracle's pages and place them in their Java VM. As you stated your manager does not allow this, there is only one way left - you have to use (only) 16 byte long AES keys.

Security warning: due to upcoming Quantum computers, the actual recommendation for AES keys is 32 byte long keys.

code:

import javax.crypto.Cipher;
import java.security.NoSuchAlgorithmException;
import java.security.Security;

public class UnlimitedCryptoPoliciesCheck {
    public static void main(String[] args) throws NoSuchAlgorithmException {
        System.out.println("Check for unlimited crypto policies");
        //Security.setProperty("crypto.policy", "limited"); // muss ganz am anfang gesetzt werden !
        System.out.println("restricted cryptography: " + restrictedCryptography() + " Notice: 'false' means unlimited policies"); // false mean unlimited crypto
        System.out.println("Security properties: " + Security.getProperty("crypto.policy"));
        int maxKeyLen = Cipher.getMaxAllowedKeyLength("AES");
        System.out.println("Max AES key length = " + maxKeyLen);
  }

    /**
     * Determines if cryptography restrictions apply.
     * Restrictions apply if the value of {@link Cipher#getMaxAllowedKeyLength(String)} returns a value smaller than {@link Integer#MAX_VALUE} if there are any restrictions according to the JavaDoc of the method.
     * This method is used with the transform <code>"AES/CBC/PKCS5Padding"</code> as this is an often used algorithm that is <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#impl">an implementation requirement for Java SE</a>.
     *
     * @return <code>true</code> if restrictions apply, <code>false</code> otherwise
     * https://stackoverflow.com/posts/33849265/edit, author Maarten Bodewes
     */
    public static boolean restrictedCryptography() {
        try {
            return Cipher.getMaxAllowedKeyLength("AES/CBC/PKCS5Padding") < Integer.MAX_VALUE;
        } catch (final NoSuchAlgorithmException e) {
            throw new IllegalStateException("The transform \"AES/CBC/PKCS5Padding\" is not available (the availability of this algorithm is mandatory for Java SE implementations)", e);
        }
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

As correctly noted in a comment, 8u161 up no longer needs the policy download; see the release notes and download page. OP claims to be using 8u181 which is above 161. Running exactly that code on my (archived) copy of 8u181 gets the unlimited result. OTOH you are correct crypto.policy is a security property and any system property by that name is irrelevant and inapplicable.
0

Though it was displaying jre1.8.0_181 in cmd but my project was running on jre1.7. As @dave_thompson_085 stated I used System.properties("java.version") to get the jre version.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.