4

I am using Java AES encryption using

SecretKeySpec(byte[] key, String algorithm) 

to generate a Key object.

After I encrypt something, I want to remove the Key from memory.

I can remove all references to the Key, but that does not guarantee that the key is not floating somewhere in memory.

I can "zero out" the byte[] array that I used to generate the Key, but how can I zero out or flush the actual Key memory.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
adamM
  • 1,116
  • 10
  • 29
  • AFAIK, there is no way to explicitly tell java's GC to clean up a specific object, nor is there a way to explicitly invoke it. You can only provide hints by requesting that it be done. I suppose you could reduce the possible time it could spend in memory by tuning how aggressive the GC is, but beyond that I dont think its possible. Heres a blog post about GC tuning that may help: http://www.cubrid.org/blog/dev-platform/how-to-tune-java-garbage-collection/ – Mark W Mar 06 '15 at 20:51
  • 1
    @MarkW, garbage collection won't zero out the key material anyway. It will only make that memory available to _maybe_ be re-used later. In fact, even if there was a method to zeroize the Key object, the GC is still a problem, because it could have moved the object before the zeroize method was called, and that would leave a copy of the key material behind in the old location. – Solomon Slow Mar 06 '15 at 20:54
  • 1
    @jameslarge Agreed... I suspect the only way may be to actually fill the available memory with some arbitrary values which are then immediately GCed, but its a horrible solution. I'll have to follow this question and see if anyone else knows a real way to accomplish it. – Mark W Mar 06 '15 at 20:57
  • It seems like the point of using a byte[] in the constructor is that the object used to generate the key can be zeroed, but then the key still floats around in memory. I do not want to have to cal GC afterwards as that will garantee nothing, and will be slow. – adamM Mar 06 '15 at 20:59
  • See also https://stackoverflow.com/questions/7191906/how-do-i-zero-ise-a-secret-key-in-java – DNA Mar 06 '15 at 21:09

2 Answers2

4

There doesn't appear to be a way to do this in Java versions up to 7, but it has been fixed for Java 8 by adding the Destroyable interface.

See https://bugs.openjdk.java.net/browse/JDK-6263419

Addess this requirement by enhancing java.security.PrivateKey and javax.crypto.SecretKey classes to extend the javax.security.auth.Destroyable interface.

However, note the comments:

clearing out a BigInteger or byte[] reference doesn't guarantee that the sensitive information is gone from memory. The operating system's virtual memory may have been swapped to disk, for example, leaving a copy on the local hard drive. In addition, the Java runtime VM may itself have multiple internal copies of the information.

Note also that zeroing out the original byte array will NOT clear the SecretKeySpec, because it takes a copy of the byte array in its constructor.

However, you might be able to get access to the SecretKeySpec copy of the byte array (even though it is private) using Java Reflection to change the access to that field.

DNA
  • 42,007
  • 12
  • 107
  • 146
  • The destroyable interface simply makes the object unable to be called after destroy(), right? It does not affect the actual "contents" of the object in memory. If a dump of the memory is performed, one could still obtain the contents of the Key, even if the object is destroyed(), right? – adamM Mar 06 '15 at 21:21
  • It *should* clear byte arrays: [JavaDoc](https://docs.oracle.com/javase/8/docs/api/javax/security/auth/Destroyable.html) says "Sensitive information associated with this Object is destroyed or cleared. Subsequent calls to certain methods on this Object will result in an IllegalStateException being thrown" ... and " Implementations should override the default destroy and isDestroyed methods from the Destroyable interface to enable sensitive key information to be destroyed, cleared, or in the case where such information is immutable, unreferenced." – DNA Mar 06 '15 at 21:24
  • I think you are correct here. Nice! Guess it is time to upgrade to Java 8 ! – adamM Mar 06 '15 at 21:31
3

If Java 8 isn't available to you, you're going to need to be a little creative. Namely, picking the correct tool for the job. In this case, I'd recommend C. C gives you complete access to the actual memory; Java abstracts almost all of that away from you. So the explanation would be as follows:

As is pointed out in the comments, there are more implementation level details that arise. The point of this answer is to highlight that other languages do this much better and it might be worth looking into.

Community
  • 1
  • 1
christopher
  • 26,815
  • 5
  • 55
  • 89
  • It doesnt solve the issue of GC moving it around, independent thread stacks having made copies, or virtual memory though right? – Mark W Mar 06 '15 at 21:20
  • Yeah. I was more trying to get across the principle that maybe Java isn't the language for the job. Perhaps I got a little too specific, at which point these issues arise. I'll edit. – christopher Mar 06 '15 at 21:21