java.security.InvalidKeyException – How to solve InvalidKeyException
In this example we are going to talk about java.security.InvalidKeyException
. It is probably the most common exception you will stumble upon when handling encryption in your Java application. java.security.InvalidKeyException
is a subclass of java.security.KeyException
which in turn is a subclass of java.security.GeneralSecurityException
.
As the name suggests, InvalidKeyException
emerges when there is something wrong with the encryption key you are trying to use in one of your encryption algorithms. Most common problems with encryption keys include wrong length of the key, invalid encoding, and of course wrong initialization of the key (probably the key is NULL
…).
To demonstrate this Exception we are going to create a simple application with a utility class that is able of performing AES encryption.
1. A simple Encryption/Decryption Application
The purpose of this example is not to dive deep in the AES encryption standard, nor to the implementation of this algorithm in Java. Nevertheless here is a simple utility class that can encrypt and decrypt a Java String
, considered as the plaintext.
AESUtils.java:
package com.javacodegeeks.core.security; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; public class AESUtils { static String INITIALIZATIO_VECTOR = "AODVNUASDNVVAOVF"; public static byte[] encrypt(String plainText, String encryptionKey) throws Exception { Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE"); SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES"); cipher.init(Cipher.ENCRYPT_MODE, key,new IvParameterSpec(INITIALIZATIO_VECTOR.getBytes("UTF-8"))); return cipher.doFinal(plainText.getBytes("UTF-8")); } public static String decrypt(byte[] cipherText, String encryptionKey) throws Exception{ Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE"); SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES"); cipher.init(Cipher.DECRYPT_MODE, key,new IvParameterSpec(INITIALIZATIO_VECTOR.getBytes("UTF-8"))); return new String(cipher.doFinal(cipherText),"UTF-8"); } }
This class has to static utility methods :
encrypt:
Takes the plain text and the encryprion key as input and produces the cipher text withUTF-8
encoding.decrypt:
Takes the cipher text and the encryprion key as input and produces the plain text withUTF-8
encoding.
package com.javacodegeeks.core.security; public class InvalidKeyExceptionExample { static String PLAIN_TEXT = "Java Code Geeks Rock!\0\0\0\0\0\0\0\0\0\0\0"; static String ENCRYPTION_KEY = "0123456789abcdef"; public static void main(String [] args) { try { System.out.println("Plain text:" + PLAIN_TEXT); byte[] cipherText = AESUtils.encrypt(PLAIN_TEXT, ENCRYPTION_KEY); System.out.print("Cipher Text: "); for (int i=0; i<cipherText.length; i++) System.out.print( String.format("%02X ",cipherText[i])); System.out.println(""); String decrypted = AESUtils.decrypt(cipherText, ENCRYPTION_KEY); System.out.println("Decrypted Text: " + decrypted); } catch (Exception e) { e.printStackTrace(); } } }
The above class uses the AESUtils
in order to encrypt and decrypt a String
. Here is the output when you run it:
Plain text :Java Code Geeks Rock! Cipher Text: 22 01 BF DB 8E F5 CD 85 99 42 CE 3C 25 4F 05 54 7B EB FC 3C 2F F4 7C 36 AC 7F F4 DC 3E A7 A5 55 Decrypted Text : Java Code Geeks Rock!
2. A simple example of InvalidKeyException
Now, by default JDK 1.7, can use AES 128-bit encryption, which means that the key has to be 128 bits long. Additionally the plain text has to be a multiple of 16 – that is why you see some null padding at the end of PLAIN_TEXT
. So now, Let’s try to double the size of the encryption key to 256 bits. You can quickly do that :
Change
static String ENCRYPTION_KEY = "0123456789abcdef";
to
static String ENCRYPTION_KEY = "0123456789abcdef0123456789abcdef";
Here is the output when you run it:
Plain text :Java Code Geeks Rock! java.security.InvalidKeyException: Illegal key size at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1024) at javax.crypto.Cipher.init(Cipher.java:1345) at javax.crypto.Cipher.init(Cipher.java:1282) at com.javacodegeeks.core.security.AESUtils.encrypt(AESUtils.java:14) at com.javacodegeeks.core.security.InvalidKeyExceptionExample.main(InvalidKeyExceptionExample.java:13)
So by default the key size is not supported. This is the most common case of InvalidKeyException
.
Another common case as well is when the encryption key is not a power of 2 (in most modern implementation the key should be at least 56 bits). For example:
Change
static String ENCRYPTION_KEY = "0123456789abcdef0123456789abcdef";
to
static String ENCRYPTION_KEY = "0123456789abcde";
Here is the output when you run it:
Plain text :Java Code Geeks Rock! java.security.InvalidKeyException: Invalid AES key length: 15 bytes at com.sun.crypto.provider.AESCipher.engineGetKeySize(AESCipher.java:372) at javax.crypto.Cipher.passCryptoPermCheck(Cipher.java:1052) at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1023) at javax.crypto.Cipher.init(Cipher.java:1345) at javax.crypto.Cipher.init(Cipher.java:1282) at com.javacodegeeks.core.security.AESUtils.encrypt(AESUtils.java:14) at com.javacodegeeks.core.security.InvalidKeyExceptionExample.main(InvalidKeyExceptionExample.java:13)
3. How to solve InvalidKeyException
The first thing you should do when you come up with this exception, is check if your encryption key is correctly initialized (not NULL
). Then make sure that its length in bits is a power of two. If you want to use a String
as your encryption key you should check its length in bytes and multiply by 8 to find the length in bits. The safest way to do that is first to convert the String in a byte array and then check the array’s length. You should keep in mind that in most JVM 64-bit implementation each character in the String
takes up 2 bytes.
After checking all the above you should make sure that your encryption engine supports key of that length. If you have to use 256-AES or more here is what you should do:
- Visit Oracle’s website and put ‘Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files’ on the search box. Here is the quick link with the results I’ve got : http://tinyurl.com/m65q5ax
- Then follow the link ‘Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 7 Download’
- Download
UnlimitedJCEPolicyJDK7.zip
- Extract the folder. Inside you will find
local_policy.jar
andUS_export_policy.jar
. - Go to your Java installation directory (aka JAVA_HOME) and find :
JAVA_HOME/jre{version_number}/lib/security
. Paste these two files. Files with the same names will most probably be there already. You need to replace them with the new files.
That’s it. You can now restart your project and use 256-AES, 512-AES and so on.
Download the Source Code
This was an example on java.security.InvalidKeyException
and How to solve InvalidKeyException
.
You can download the full source code of this example here : InvalidKeyExceptionExample.zip