Reputation: 51
Why would this init succeed:
Cipher AESCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
AESCipher.init(Cipher.ENCRYPT_MODE, secretKey, secRandom);
while this fails:
Cipher AESCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
AESCipher.init(Cipher.DECRYPT_MODE, secretKey, secRandom);
Throwing an Exception in thread "main" java.security.InvalidKeyException: Parameters missing
The secretKey is generated by a KeyGenerator, and the secureRandom by SecureRandom.getInstance("SHA1PRNG") with a random static seed set.
Thanks
Upvotes: 5
Views: 10452
Reputation: 93948
Just read the JavaDoc of the init method with SecureRandom that you are applying:
If this cipher requires any algorithm parameters that cannot be derived from the given key, the underlying cipher implementation is supposed to generate the required parameters itself (using provider-specific default or random values) if it is being initialized for encryption or key wrapping, and raise an
InvalidKeyException
if it is being initialized for decryption or key unwrapping. The generated parameters can be retrieved usinggetParameters
orgetIV
(if the parameter is an IV).
You will have to transfer the encrypted IV to the decryption method, e.g. by prepending it to the cipher text. The IV may be transferred in the clear. Use IvParameterSpec
instead of SecureRandom
to set the IV for decryption.
Upvotes: 2
Reputation: 41958
As correctly surmised by CodeInChaos, the SecureRandom instance is used to derive a random IV when the AESCipher
instance is created with Cipher.ENCRYPT_MODE
. However, you supply it as a parameter when creating a Cipher instance in decrypt mode. This little pointless code fragment shows an example.
public static void main(String[] args) throws Exception {
SecureRandom secRandom = SecureRandom.getInstance("SHA1PRNG");
KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(128, secRandom);
Key secretKey = kg.generateKey();
Cipher AESCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
AESCipher.init(Cipher.ENCRYPT_MODE, secretKey, secRandom);
IvParameterSpec iv = new IvParameterSpec(AESCipher.getIV());
AESCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
AESCipher.init(Cipher.DECRYPT_MODE, secretKey,iv, secRandom);
}
Also, your claim that you are initializing your SecureRandom instance with a static seed suggest a misunderstanding of that class. SecureRandom does not guarantee that you will get the same output when you provide the same seed. If you look carefully at the Javadocs you'll see that it attempts to provide some true entropy from other sources if at all possible.
EDIT 1:
Thanks to owlstead for his usual thoroughness in reviewing answers. See his answer to a related question for additional discussion. The source code for the SHA1PRNG is available online here. It is a little tricky to follow but if you provide a seed before asking the instance for any random bytes then the output will be completely deterministic. So my earlier statement is incorrect.
Upvotes: 5