【发布时间】:2021-02-20 11:09:54
【问题描述】:
我正在编写一个函数来使用 SecretKeyFactory 基于密码生成密钥(字节)。我想在不再需要时销毁 SecretKey 实例,但它会引发异常。
try {
byte[] salt = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
PBEKeySpec keySpec = new PBEKeySpec("password".toCharArray(), salt, 1000, 256);
SecretKey secretkey = factory.generateSecret(keySpec);
byte[] key = secretkey.getEncoded();
// Using key
// Destroy key
Arrays.fill(key, (byte)0);
// Destroy secretKey
secretkey.destroy(); // --> Throw DestroyFailedException
} catch (Exception e) {
e.printStackTrace();
}
我在 Mac 上使用 Oracle JDK1.8.0_66。
我看了一下SecretKey源代码,发现了这个默认实现(SecretKey实现了Destroyable接口)
public default void destroy() throws DestroyFailedException {
throw new DestroyFailedException();
}
意思是:SecretKey的实现没有重写destroy方法来销毁内部密码字符和内部密钥字节。
这是 JDK 8 中的错误吗?
【问题讨论】:
-
根据 Java 8 API 的 SecretKey its only two known implementing classes are KerberosKey and SecretKeySpec。在这两个中,只有 KerberosKey 覆盖了 destroy()。密钥的文档还说,任何扩展类都应该覆盖 Destroyable 提供的 destroy() 方法,所以这看起来不像是错误,而是预期的行为。您知道您的 generateSecret 调用返回的实际类吗?
-
@BrandonDockery:实现是 com.sun.crypto.provider.PBKDF2KeyImpl。该类实现了继承自 SercretKey 接口的 PBEKey 接口。
-
请记住,您还应该调用 keySpec.clearPassword()(尽管这并不能解决缺少清除 SecretKey 的问题)
-
@BrandonDockery 后期评论:我认为这是一个 API 错误,因为您目前无法编写代码来调用
destroy,而且似乎没有任何方法可以测试对象是否可销毁。也许他们应该创建一个方法tryDestroy(): DestructionResult。