Clear array across all threads

Viewed 190

In Java it is recommended to use char[] for storing passwords or other sensitive information to be able to clear it manually once the data is no longer needed.

How can such an array be cleared across all threads? If I understand it correctly threads might only perform changes in their cache, but not in the shared memory, so the following would not work reliably:

char[] password = ...
...
Arrays.fill(password, '\0');
  • Is this assumption correct or do the threads always write to the shared memory?
  • Is it necessary to use volatile (or other synchronization) to make sure the shared memory is updated?
    • Is a happens-before relationship required for this because the compiler / JVM would otherwise omit memory synchronization due to optimization?
  • Do other threads have to establish a happens-before relationship to clear the array content from their cache, or is this negligible? Possibly because the cache will be used for other more frequently accessed data and the array will be discarded, given that it is not actively used anymore.

Edit: The statement that char[] should be used for passwords was based on Why is char[] preferred over String for passwords?, however after looking at it again, this is also a little bit controversial.

2 Answers

Making the array reference volatile won't guarantee volatile access to it's contents. You could use AtomicIntegerArray if you want thread safe shared access. Otherwise you might want to wrap your char array into your custom class with synchronisation around it's methods. Although the latter will be less performant.

Note the using an array of characters instead of a string might not be truly more secure. Dumping the process memory during the time when your char array contains the data is still possible if your attacker has access to your machine, and if he does, you have much more serious concerns than this. Also, garbage collection might move your data elsewhere during it's compaction phase, leaving your password in the freed 'garbage' memory that hasn't been overwritten yet (given you are talking about shared members between threads this is even more likely to happen since your char array would be considered long lived and copied to memory spaces reserved for older generation objects).

I think jbx has a good answer. If an attacker has access to your main memory, you likely have bigger problems than worrying about a stray password string in memory. Worrying also about L3 cache seems rather overwrought.

But in the interest of code, I'll point out that while making an array volatile won't help, nearly every other form of synchronization will help. They all have semantics that require that all writes be made visible. So you can guarantee that changes to an array are visible.

public class Password {

  private final char[] password;

  public Password( char[] p ) {
     password = Arrays.copy( p, p.length );
  }

  public synchronized boolean compare( char[] p ) {
      return Arrays.equal( password, p );
  }

  public synchronized clear() {
    Arrays.fill(password, 42 );
  }
}

Code was not tested.

Here I use synchronized just to provide memory visibility. The atomicity is just a side effect and probably isn't needed.

Related