为什么我的AES Cipher会在init的DECRYPT_MODE上抛出一个InvalidKeyException

时间:2013-01-02 15:14:54

标签: java encryption aes secret-key initialization-vector

为什么这个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”)生成,带有随机静态种子集。

由于

2 个答案:

答案 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   它正在初始化以进行解密或密钥解包。该   可以使用getParametersgetIV检索生成的参数   (如果参数是IV)。

您必须将加密的IV传输到解密方法,例如通过将其添加到密文。 IV可以清楚地转移。使用IvParameterSpec代替SecureRandom设置IV进行解密。