views:

100

answers:

4

My concern is that cryptographic keys and secrets that are managed by the garbage collector may be copied and moved around in memory without zeroization.

As a possible solution, is it enough to:

public class Key {
  private char[] key;
  // ...
  protected void finalize() throws Throwable { 
    try {
      for(int k = 0; k < key.length; k++) {
        key[k] = '\0';
      }
    } catch (Exception e) {
      //...
    } finally {
      super.finalize();
    }
  }
  // ...
}

EDIT: Please note that my issue is regarding not only zeroization of the official (referenced) copy of the object, but also any stale copies the garbage collector may have made while it shuffles memory around for space and speed efficiency.

The simplest example is the mark-and-sweep GC, where objects are marked as 'referenced' and then all those objects are copied to another region. The rest are then garbage and so they are collected. When the copy happens, that might leave residual key data that isn't being managed anymore by the garbage collector (because the 'official' data is in the new region).

A litmus test for this would be if you use a key in the crypto module, zeroize the key, then inspect the entire JVM process space, you should not find that key.

+4  A: 

The Java Cryptography Extension Reference Guide advises always using character arrays instead of strings for passwords so that they can be zeroed afterwards. They also provide a code example of how you could implement it.

Mark Byers
This is a very good point, but I'm not sure it's enough. Please see me recent update to the question.
Jeremy Powell
Overwriting the content of an array is not enough with newer Java VMs, as the array can be moved around within the process' memory space, e.g. if the heap is defragmented.
jarnbjo
+1  A: 

You best bet is to use allocateDirect in NIO. On a sane implementation, that should not be moved about. But it'll probably be eligible for paging out to disk (you could poll it, I guess) and hibernation.

Tom Hawtin - tackline
A: 

So I've come to the conclusion, from @jambjo and @james, that there really isn't anything I can do to prevent keys from being copied and becoming unaccounted for.

The best strategy, as a developer, would be to drop the crypto library down into C (or any other non-managed language) and implement your stuff there.

I would be more than willing to accept an answer from someone else if they could come up with a better solution.

Jeremy Powell
+1  A: 

So what if the data in memory is not overwritten at a specific time? If you have to worry about an attacker reading your machine's memory, that's the problem, not what he could find there at what time.

What actual attack scenario are you worried about where keys left somwhere in the memory of a JVM could be a serious problem? If an attacker can look at the JVM's memory, he can just as well catch those keys while you're still using them.

And if you're worried about an attacker running as a regular user on the system getting hold of memory discarded by the JVM: AFAIK all modern OSs overwrite newly allocated memory with zeroes.

Michael Borgwardt
First, the idea is simply risk mitigation. The less time you have the key in memory, the less chances it'll have to get seen by an attacker. However, yes you are absolutely correct. This problem I have is quite contrived. FIPS 140-2 requirements are derived from hardware requirements, where _everyone_ is assumed to have access to the hardware, so you want to reduce the attack window. For a software module, this doesn't make as much sense.
Jeremy Powell