我正在编写一个函数,使用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中的错误吗?
答案 0 :(得分:2)
你是对的。 verbatim string literal类不实现从Destroyable继承的destroy方法。 PBKDF2KeyImpl。
这不一定是JDK中的错误,因为It also looks like you are not the first person to be concerned by this的API明确地将它留给实现类来定义这种行为,尽管这种行为没有被覆盖似乎有点奇怪。
答案 1 :(得分:0)
这对我来说非常糟糕。我也在寻找破坏SecretKey的方法。用反射怎么样?我知道这是超级hacky,但它允许我们获得底层私钥组:
public class DestroyableSecretKeySpec extends SecretKeySpec {
public DestroyableSecretKeySpec( byte[] key, int offset, int len, String algorithm ) {
super( key, offset, len, algorithm );
}
@Override
public void destroy() {
try {
// Use hacky reflection to clear the underlying private key from memory.
// This is so ugly :/
Field f = SecretKeySpec.class.getDeclaredField( "key" );
f.setAccessible(true);
byte[] key = (byte[]) f.get( this );
Arrays.fill( key, (byte)0xCC );
} catch( NoSuchFieldException | IllegalAccessException e ) {
throw new EncryptionException( "Can't use reflection to clear a secret key.", e );
}
}
}
你认为这有什么问题吗?