9

I am trying to create an AES encryption method, but for some reason I keep getting

java.security.InvalidKeyException: Key length not 128/192/256 bits

Here is the code:

public static SecretKey getSecretKey(char[] password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException{
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
    // NOTE: last argument is the key length, and it is 256
    KeySpec spec = new PBEKeySpec(password, salt, 1024, 256);
    SecretKey tmp = factory.generateSecret(spec);
    SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
    return(secret);
}


public static byte[] encrypt(char[] password, byte[] salt, String text) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidParameterSpecException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException{
    SecretKey secret = getSecretKey(password, salt);

    Cipher cipher = Cipher.getInstance("AES");

    // NOTE: This is where the Exception is being thrown
    cipher.init(Cipher.ENCRYPT_MODE, secret);
    byte[] ciphertext = cipher.doFinal(text.getBytes("UTF-8"));
    return(ciphertext);
}

Can anyone see what I am doing wrong? I am thinking it may have something to do with the SecretKeyFactory algorithm, but that is the only one I can find that is supported on the end system I am developing against. Any help would be appreciated. Thanks.

Duncan Jones
  • 67,400
  • 29
  • 193
  • 254
wuntee
  • 12,170
  • 26
  • 77
  • 106
  • 1
    Can you please paste the exception? – Kaleb Pederson Apr 02 '10 at 19:59
  • There is an answer in an earlier post at [this link](http://stackoverflow.com/questions/992019/java-256bit-aes-encryption/992413#992413). Hope this helps! – Etamar Laron Apr 02 '10 at 20:23
  • so, it seems that the java instance does not support what i need: 'A java.security.InvalidKeyException with the message "Illegal key size or default parameters" ' – wuntee Apr 02 '10 at 20:42
  • Also, is it a limitation on the Cipher, or the SecretKey? – wuntee Apr 02 '10 at 20:44
  • While this may theoretically answer the question, [it would be preferable](http://meta.stackexchange.com/q/8259) to include the essential parts of the answer here, and provide the link for reference. – Matt Ball May 03 '12 at 23:51

5 Answers5

8

For a stronger key strength encryption you would need to download Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files.

http://java.sun.com/javase/downloads/index.jsp (Check Other Downloads).

Mohamed Mansour
  • 39,445
  • 10
  • 116
  • 90
  • I have downloaded the extra jars, added them to the project, but am still getting the exception... – wuntee Apr 03 '10 at 22:48
  • You don't add them to the project, those are runtime libraries. The README.txt file states that you have to install them to your runtime security folder (overwrite the files there) If your using JDK then: /path/to/jdk/jre/libs/security/ If your using JRE instead: /path/to/jre/libs/security/ – Mohamed Mansour Apr 06 '10 at 23:46
4

The problem here is the mismatch between key sizes for your key derivation function and the given ciphers. The PBKDF you use is "PBEWithMD5AndDES" and in this string the DES part indicates the type of output. As single DES as it is known uses only 8 byte keys (64 bit, 56 effective bit size with parity bits). AES keys should be either 128, 192 and 256 bit and should not include parity bits.

To create AES strength key sizes you should at least use PBKDF2 instead of PBKDF1, preferably with SHA-256 or SHA-512 for higher key sizes. For 128 bit keys you should however be fine with SHA-1. So use the build in "PBKDF2WithHmacSHA1" SecretKeyFactory instead. Note that PBKDF2 / SHA1 with keys over 160 bit will result in suboptimal operation. You may want to use a simple key based key derivation function (KBKDF) over the output if you want to create more data (such as a separate IV).

As others have indicated, if you use keys of over 128 bit you will need the unlimited crypto jurisdiction files.


Notes on the following code:

  • No integrity protection, which you may need even for maintaining confidentiality
  • CBC using a zero IV, this may be OK but only if the salt is fully random (store the salt with the ciphertext)
  • 1024 is a relatively low number of iterations for the PBKDF2
  • PBKDF2 is incompatible with PBKDF1 which you were using
public static SecretKey getSecretKey(char[] password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException{
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    // NOTE: last argument is the key length, and it is 128
    KeySpec spec = new PBEKeySpec(password, salt, 1024, 128);
    SecretKey tmp = factory.generateSecret(spec);
    SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
    return(secret);
}

public static byte[] encrypt(char[] password, byte[] salt, String text) throws GeneralSecurityException {
    SecretKey secret = getSecretKey(password, salt);
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(new byte[cipher.getBlockSize()]));
    byte[] ciphertext = cipher.doFinal(text.getBytes(StandardCharsets.UTF_8));
    return(ciphertext);
}
Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
2

You can install the JCE Unlimited Strength jars, as is suggested on several other similar questions, or just try including this code in your main function or driver.

try {
    java.lang.reflect.Field field = Class.forName("javax.crypto.JceSecurity").getDeclaredField("isRestricted");
    field.setAccessible(true);
    field.set(null, java.lang.Boolean.FALSE);
} catch (Exception ex) {
    ex.printStackTrace();
}
Sean
  • 2,315
  • 20
  • 25
-1

using any padding mechanisms to fill the empty bits

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
Wajdy Essam
  • 4,280
  • 3
  • 28
  • 33
-1

When I place the following code and run it, I don't receive any exceptions:

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import java.security.spec.KeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;


public class Main 
{
    public static void main(String[] args)
    {
        String pass = "this is the pass";
        char[] pw = new char[pass.length()];
        for(int k=0; k<pass.length();++k)
        {
            pw[k] = pass.charAt(k); 
        }
        try {
            byte[] q = encrypt(pw,"asdf".getBytes(),"der text");
            System.out.println(new String(q));
        } catch (InvalidKeyException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvalidParameterSpecException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (BadPaddingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    public static SecretKey getSecretKey(char[] password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException{
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
        // NOTE: last argument is the key length, and it is 256
        KeySpec spec = new PBEKeySpec(password, salt, 1024, 256);
        SecretKey tmp = factory.generateSecret(spec);
        SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
        return(secret);
    }


    public static byte[] encrypt(char[] password, byte[] salt, String text) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidParameterSpecException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException{
        SecretKey secret = getSecretKey(password, salt);

        Cipher cipher = Cipher.getInstance("AES");

        // NOTE: This is where the Exception is being thrown
        cipher.init(Cipher.ENCRYPT_MODE, secret);
        byte[] ciphertext = cipher.doFinal(text.getBytes("UTF-8"));
        return(ciphertext);
    }
}

I was never able to recreate the exception that you had. I'm running J2SE 1.6 and developing on Eclipse.

Could it be that your password is not 16 bytes long?

Chopstick
  • 215
  • 1
  • 6
  • I have not removed any protection. The encrypt() method calls getSecretKey() which calls the PBEKeySpec() just as the OP has in his original code. – Chopstick Jan 05 '14 at 18:01