I am trying to generate a key using Java. To be honest I am not that experienced with keys, password, ciphers and encryption.
And from whatever I have searched from this site, I see it as a very common problem. I did some reading and came up with this code that I wrote:
Security.setProperty("crypto.policy", "unlimited"); String valueToEncode = "some_random_text"; SecureRandom secureRandom = new SecureRandom(); byte[] salt = new byte[256]; secureRandom.nextBytes(salt); KeySpec keySpec = new PBEKeySpec("some_random_password".toCharArray(), salt, 65536, 256); // AES-256 SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBEWITHHMACSHA512ANDAES_256"); byte[] key = secretKeyFactory.generateSecret(keySpec).getEncoded(); SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES"); byte[] ivBytes = new byte[16]; secureRandom.nextBytes(ivBytes); IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); byte[] encValue = cipher.doFinal(valueToEncode.getBytes(StandardCharsets.UTF_8)); 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); System.out.println(finalCiphertext.toString());
This is modified from an answer that I saw on another post. But I still get the “invalid length” error.
The error that I get is:
Exception in thread "main" java.security.InvalidKeyException: Invalid AES key length: 20 bytes at com.sun.crypto.provider.AESCrypt.init(AESCrypt.java:87) at com.sun.crypto.provider.CipherBlockChaining.init(CipherBlockChaining.java:93) at com.sun.crypto.provider.CipherCore.init(CipherCore.java:591) at com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:346) at javax.crypto.Cipher.implInit(Cipher.java:805) at javax.crypto.Cipher.chooseProvider(Cipher.java:863) at javax.crypto.Cipher.init(Cipher.java:1395) at javax.crypto.Cipher.init(Cipher.java:1326) at com.att.logicalprovisioning.simulators.Trial.main(Trial.java:47)
Trial.java:47
being the line: cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
Is there a one-size fits all solution to this? Or is it just my lack of understanding?
Any help would be appreciated.
Advertisement
Answer
Your key is 20 bytes long because secretKeyFactory.generateSecret(keySpec).getEncoded()
returns the password some_random_password
.
An easy way to fix the code is to use the key derivation PBKDF2WithHmacSHA512
instead of PBEWITHHMACSHA512ANDAES_256
. This generates a key of the specified length based on the password and salt:
... SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512"); ...
However, PBEWITHHMACSHA512ANDAES_256
can also be applied. This algorithm specifies a key derivation with PBKDF2WithHmacSHA512
and subsequent AES encryption. The implementation is functionally identical to yours, but requires a few more changes to the code:
... IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes); PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, 65536, ivParameterSpec); PBEKeySpec keySpec = new PBEKeySpec("some_random_password".toCharArray()); SecretKeyFactory kf = SecretKeyFactory.getInstance("PBEWITHHMACSHA512ANDAES_256"); SecretKey secretKey = kf.generateSecret(keySpec); Cipher cipher = Cipher.getInstance("PBEWITHHMACSHA512ANDAES_256"); cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec); byte[] encValue = cipher.doFinal(valueToEncode.getBytes(StandardCharsets.UTF_8)); ...
Two other issues are:
- You are using a 256 bytes salt, but only storing 16 bytes when concatenating. To be consistent with the concatenation, apply a 16 bytes salt:
byte[] salt = new byte[16]
. - The output
finalCiphertext.toString()
returns only class and hex hashcode of the object, s. here. For a meaningful output use a Base64 or hex encoding of thebyte[]
instead, e.g.Base64.getEncoder().encodeToString(finalCiphertext)
.