Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to clear content of java.security.Key?

when you use sensitive data in Java application, it is often advised to your primitive types - e.g. use char[] instead of String ...

But with cryptography keys we generally need to use java.security.Key objects because that's what JCE providers use. Key is very often very sensitive piece of information and we'd like to be able to minimize the window of possible attack - i.e. create Key object as late as possible , do the encryption/decryption/signing and then as soon as possible clear the object. But Key doesn't provide any method which would facilite this clearing.

Currently we're doing it in a way that we keep the key in byte array and initialize the Key object right before using it, Key immediately falls out of scope to be eligible for garbage collection and we also immediately clear the byte array. But this doesn't seem very elegant ... It also fills creates a dichotomy in our interfaces - some accept byte array, some accept Key objects and it's kind of a mess.

I am aware of the fact that Java doesn't provide any general mechanism to clear objects from memory, but I'm asking if there is something specifically for Keys. Alternatively, is there some other approach to minimize attack window for Keys?

Thanks.

like image 402
qbd Avatar asked Sep 03 '14 11:09

qbd


1 Answers

Upgrade to Java 8 where SecretKey and RSAPrivateKey implements Destroyable. However, a quick test shows that this doesn't work for AES keys nor RSA private keys generated locally.

The following code does work, but it fails only after the second init (!) so beware that key information may be cached (AES requires sub-key derivation, so the sub keys may linger on). It may be a good idea to re-init any cipher with a separate (zero) key after use. Furthermore, it does not protect against copying of the data by the VM itself, e.g. during memory compaction after garbage collection.

MyAESKey myAESKey = new MyAESKey(new byte[16]);
Cipher aes = Cipher.getInstance("AES");
aes.init(Cipher.ENCRYPT_MODE, myAESKey);
aes.doFinal("owlstead".getBytes());
myAESKey.destroy();
aes.doFinal("owlstead".getBytes());
aes.init(Cipher.ENCRYPT_MODE, myAESKey);
aes.doFinal("owlstead".getBytes());

where MyAESKey implements both SecretKey and Destroyable. Don't forget to destroy the input to the MyAESKey as well though. You could of course use a similar approach with your own MyDestroyable interface for Java 7 and below.

The only other method that I know of is to use a provider that uses a security token (HSM / TPM / smart card etc.) where the key does not leave the device. In that case the key may not be destroyed either, but it is at least not available.

Providers that use native code (which uses the right kind of memory) may also allow for destruction of key data. But even outside the VM it may be hard to ensure that the key data is not left anywhere in RAM or (swap) disk.

like image 139
Maarten Bodewes Avatar answered Sep 17 '22 01:09

Maarten Bodewes