14

When running below programme i am getting this exception. Not able to figure out what the issue as AES allows the 128 -256 bit key?

 Exception in thread "main" java.security.InvalidKeyException: Invalid AES key length: 29 bytes
at com.sun.crypto.provider.AESCipher.engineGetKeySize(DashoA13*..)
at javax.crypto.Cipher.b(DashoA13*..)

Getting exception at line 20

Here is the programme

 import java.security.Key;

 import javax.crypto.Cipher;
 import javax.crypto.spec.SecretKeySpec;

 import sun.misc.BASE64Decoder;
 import sun.misc.BASE64Encoder;

 public class AESEncryptionDecryptionTest {

   private static final String ALGORITHM       = "AES";
   private static final String myEncryptionKey = "ThisIsSecurityKey";
   private static final String UNICODE_FORMAT  = "UTF8";

   public static String encrypt(String valueToEnc) throws Exception {
 Key key = generateKey();
 Cipher c = Cipher.getInstance(ALGORITHM);
 c.init(Cipher.ENCRYPT_MODE, key);  //////////LINE 20
 byte[] encValue = c.doFinal(valueToEnc.getBytes());
 String encryptedValue = new BASE64Encoder().encode(encValue);
 return encryptedValue;
   }

public static String decrypt(String encryptedValue) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.DECRYPT_MODE, key);
byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedValue);
byte[] decValue = c.doFinal(decordedValue);
String decryptedValue = new String(decValue);
return decryptedValue;
}

private static Key generateKey() throws Exception {
byte[] keyAsBytes;
keyAsBytes = myEncryptionKey.getBytes(UNICODE_FORMAT);
Key key = new SecretKeySpec(keyAsBytes, ALGORITHM);
return key;
}

public static void main(String[] args) throws Exception {

String value = "password1";
String valueEnc = AESEncryptionDecryptionTest.encrypt(value);
String valueDec = AESEncryptionDecryptionTest.decrypt(valueEnc);

System.out.println("Plain Text : " + value);
System.out.println("Encrypted : " + valueEnc);
System.out.println("Decrypted : " + valueDec);
}

}
M Sach
  • 33,416
  • 76
  • 221
  • 314

2 Answers2

32

AES allows 128, 192 or 256 bit key length. That is 16, 24 or 32 byte. Try taking just the first 16 bytes of your mEncryptionKey as the keyAsBytes.

Edit:
An after though occurred to me. A habit I have formed, and one which I recommend, is to take a SHA hash of a password/passphrase, and use that as the source bytes of your key. Taking a hash guarantees the key data will be the correct size, irrespective of the length of the password/passphrase. Your current implementation of using the String bytes has two problems;

  • It will break your key generation if someone uses a short password.
  • Two different passwords for which the first 16 bytes are the same will create the same key.

Both of these problems are eliminated by using a hash.

Take a look at the buildKey() method in this class; https://github.com/qwerky/DataVault/blob/master/src/qwerky/tools/datavault/DataVault.java

Qwerky
  • 18,217
  • 6
  • 44
  • 80
  • Thanks Qwerky. Some more findings.When i give myEncryptionKey as 16 character long i.e 128 bit length this program run fines but when i give it as 24 charecter long(192 bit length) or 32 character long(256 bit length ) then i get the error as "Illegal key size or default parameters". Can i set the key length to 256 or 192 if i want? – M Sach May 31 '12 at 11:07
  • 2
    To use 192 or 256 you may need to enable "unlimited key strength" policy files. This is due to a legal restriction in the United States. See here; http://java.sun.com/developer/technicalArticles/Security/AES/AES_v1.html. Search `Illegal key size or default parameters` on this site, there are several questions and answers about it. – Qwerky May 31 '12 at 11:20
  • In your example in Datavault.java, BouncyCastleProvider is used which is not standard java class. Due to some restrictions i need to go only with standar java classes. Can i use some other implementation of provider class instaed of BouncyCastleProvider in the example you hav epointed out? – M Sach May 31 '12 at 11:27
  • 1
    If the goal is to make the key based on some input like user's password, hashing is good but PBKDF2 is better. If possible, use per-key random salt and save it for next time you use the same key. If that's not possible, try to use some per-user unique data (e.g. username) as salt. This helps protect you against rainbow table attacks. See here for an example http://stackoverflow.com/questions/2375541/password-verification-with-pbkdf2-in-java – John Watts May 31 '12 at 11:33
  • Actually, I'm getting `java.security.InvalidKeyException: Invalid key length: 32 bytes` for SHA. – Tomáš Zato Mar 26 '15 at 01:56
  • @TomášZato: Do you have "unlimited key strength" enabled? See Qwerky's comment about 256-bit key length. – LarsH Jun 07 '18 at 23:19
  • I'm not convinced that using a hash of a password is cryptographically secure enough, although it's probably not much worse than using the password itself. But I think nowadays, if you have to make a secret key from a password, the recommended way is to use something like `new PBEKeySpec(password, salt, 10000, 256)`; – LarsH Jun 07 '18 at 23:21
1

The key uses randomness as input, but there are stiill requirements for how it is composed. The SecretKeySpec constructor you used is for loading an already generated key into memory. Instead, use KeyGenerator.

KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM);
kg.init(128);
SecretKey k = kg.generateKey();

Also note that AES-128 is now actually thought to be weaker than AES-256. It probably isn't drastically different but the benefit from the longer key size may be outweighed by simplifications elsewhere (fewer rounds).

John Watts
  • 8,717
  • 1
  • 31
  • 35
  • 2
    Hi John. I want to to use the self assigned key as i will be using as shared key. I want to use the key which is known and asiigned by me not system generated key. Can you throw some inputs how i can use the self assigned key of any length less than 256 bit in AES? – M Sach May 31 '12 at 11:11