为什么这个init会成功:
Cipher AESCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
AESCipher.init(Cipher.ENCRYPT_MODE, secretKey, secRandom);
虽然失败了:
Cipher AESCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
AESCipher.init(Cipher.DECRYPT_MODE, secretKey, secRandom);
投掷一个 线程“main”中的异常java.security.InvalidKeyException:缺少参数
secretKey由KeyGenerator生成,secureRandom由SecureRandom.getInstance(“SHA1PRNG”)生成,带有随机静态种子集。
由于
答案 0 :(得分:5)
正如CodeInChaos正确推测的那样,SecureRandom实例用于在使用AESCipher
创建Cipher.ENCRYPT_MODE
实例时派生随机IV。但是,在解密模式下创建Cipher实例时,请将其作为参数提供。这个小小的无意义的代码片段显示了一个例子。
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);
}
此外,您声称使用静态种子初始化SecureRandom实例表明您对该类的误解。当您提供相同的种子时,SecureRandom不保证您将获得相同的输出。如果你仔细查看Javadocs,你会发现它会尽可能地从其他来源提供一些真正的熵。
编辑1:
感谢owlstead在审查答案时通常的彻底性。有关其他讨论,请参阅他的answer相关问题。 SHA1PRNG的源代码可在线获取here。接下来有点棘手,但是如果你在之前提供种子询问实例的任何随机字节,那么输出将是完全确定的。所以我之前的陈述不正确。
答案 1 :(得分:2)
请阅读您正在申请的init method with SecureRandom的JavaDoc:
如果此密码需要任何不能的算法参数 从给定密钥派生,底层密码实现是 应该自己生成所需的参数(使用 如果正在初始化,则提供者特定的默认值或随机值) 用于加密或密钥包装,并提高
InvalidKeyException
if 它正在初始化以进行解密或密钥解包。该 可以使用getParameters
或getIV
检索生成的参数 (如果参数是IV)。
您必须将加密的IV传输到解密方法,例如通过将其添加到密文。 IV可以清楚地转移。使用IvParameterSpec
代替SecureRandom
设置IV进行解密。