How to fix Invalid AES key length?
Solution 1:
Things to know in general:
-
Key != Password
-
SecretKeySpec
expects a key, not a password. See below
-
- It might be due to a policy restriction that prevents using 32 byte keys. See other answer on that
In your case
The problem is number 1: you are passing the password instead of the key.
AES only supports key sizes of 16, 24 or 32 bytes. You either need to provide exactly that amount or you derive the key from what you type in.
There are different ways to derive the key from a passphrase. Java provides a PBKDF2 implementation for such a purpose.
I used erickson's answer to paint a complete picture (only encryption, since the decryption is similar, but includes splitting the ciphertext):
SecureRandom random = new SecureRandom();
byte[] salt = new byte[16];
random.nextBytes(salt);
KeySpec spec = new PBEKeySpec("password".toCharArray(), salt, 65536, 256); // AES-256
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] key = f.generateSecret(spec).getEncoded();
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
byte[] ivBytes = new byte[16];
random.nextBytes(ivBytes);
IvParameterSpec iv = new IvParameterSpec(ivBytes);
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, keySpec, iv);
byte[] encValue = c.doFinal(valueToEnc.getBytes());
byte[] finalCiphertext = new byte[encValue.length+2*16];
System.arraycopy(ivBytes, 0, finalCiphertext, 0, 16);
System.arraycopy(salt, 0, finalCiphertext, 16, 16);
System.arraycopy(encValue, 0, finalCiphertext, 32, encValue.length);
return finalCiphertext;
Other things to keep in mind:
- Always use a fully qualified Cipher name.
AES
is not appropriate in such a case, because different JVMs/JCE providers may use different defaults for mode of operation and padding. UseAES/CBC/PKCS5Padding
. Don't use ECB mode, because it is not semantically secure. - If you don't use ECB mode then you need to send the IV along with the ciphertext. This is usually done by prefixing the IV to the ciphertext byte array. The IV is automatically created for you and you can get it through
cipherInstance.getIV()
. - Whenever you send something, you need to be sure that it wasn't altered along the way. It is hard to implement a encryption with MAC correctly. I recommend you to use an authenticated mode like CCM or GCM.
Solution 2:
I was facing the same issue then i made my key 16 byte and it's working properly now. Create your key exactly 16 byte. It will surely work.
Solution 3:
You can verify the key length limit:
int maxKeyLen = Cipher.getMaxAllowedKeyLength("AES");
System.out.println("MaxAllowedKeyLength=[" + maxKeyLen + "].");