5

为什么这个初始化会成功:

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") 与随机静态种子集生成。

谢谢

4

2 回答 2

5

正如 CodeInChaos 正确推测的那样,SecureRandom 实例用于在使用AESCipher创建实例时派生随机 IV Cipher.ENCRYPT_MODE。但是,您在以解密模式创建 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 在审查答案时一贯的彻底。有关其他讨论,请参阅他对相关问题的回答。SHA1PRNG 的源代码可在此处在线获取。这有点棘手,但是如果您在向实例询问任何随机字节之前提供种子,那么输出将是完全确定的。所以我之前的说法是不正确的。

于 2013-01-02T19:37:51.310 回答
2

只需使用您正在应用的 SecureRandom 阅读 init 方法的 JavaDoc:

如果此密码需要任何不能从给定密钥派生的算法参数,则底层密码实现应该自己生成所需的参数(使用特定于提供程序的默认值或随机值),如果它正在初始化以进行加密或密钥包装,并且InvalidKeyException如果它正在为解密或密钥解包而初始化,则引发一个。可以使用getParametersor检索生成getIV 的参数(如果参数是 IV)。

您必须将加密的 IV 传输到解密方法,例如将其添加到密文中。IV可以以明文形式转移。使用IvParameterSpec而不是SecureRandom设置IV进行解密。

于 2013-01-03T17:48:52.627 回答