I am trying to clear my Secretkey after decrypting.
From what I've read, SecretKeys can be destroyed via the destroy method since Java 8.
I am using Java 14 so it should be possible.
However, whenever I use the destroy method on a key, a DestroyFailedException is thrown.
I've also seen that people ignore that Exception in their code, however, if I were to do that, I am able to print the Key after calling the destroy method on it.
Here my Decryption method:
private byte[] decrypt(byte[] encryptedText, char[] password) throws InvalidKeyException,
InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException, DestroyFailedException {
ByteBuffer bb = ByteBuffer.wrap(encryptedText);
byte[] iv = new byte[ivLengthByte];
bb.get(iv);
byte[] salt = new byte[saltLengthByte];
bb.get(salt);
byte[] cipherText = new byte[bb.remaining()];
bb.get(cipherText);
SecretKey key;
key = crypto.getAESKeyFromPassword(password, salt);
Cipher cipher;
cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, key, new GCMParameterSpec(tagLengthBit, iv));
byte[] plainText = cipher.doFinal(cipherText);
Main.clearArray(password, null);
Main.clearArray(null, iv);
Main.clearArray(null, salt);
Main.clearArray(null, cipherText);
key.destroy();
cipher = null;
return plainText;
}
After calling the destroy method, I am, as said, (assuming I ignore the Exception) able to print the key via String encodedKey = Base64.getEncoder().encodeToString(key.getEncoded());
EDIT: After using my Clear method on the array, I can still print it:
byte[] temp = key.getEncoded();
Main.clearArray(null, temp);
Clear Array:
protected static void clearArray(char[] chars, byte[] bytes) {
if (chars != null) {
for (int i = 0; i < chars.length; i++) {
chars[i] = '\0';
}
}
if (bytes != null) {
for (int i = 0; i < bytes.length; i++) {
bytes[i] = 0;
}
}
}
getAESKey:
protected SecretKey getAESKeyFromPassword(char[] password, byte[] salt)
throws NoSuchAlgorithmException, InvalidKeySpecException {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
SecretKey secret = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
return secret;
}
Final Edit:
The best solution was to switch frim PBKDF2 to argon2. https://github.com/kosprov/jargon2-api Argon2 allows to use raw Hashes, then you may store that byte array in a SecureKeySpec as mentioned above, since it allows destroying of the Spec, and clear the raw Hash Array.