[Cryptography] Heartbleed and fundamental crypto programming practices

Kevin W. Wall kevin.w.wall at gmail.com
Sat Apr 12 21:18:35 EDT 2014


On Sat, Apr 12, 2014 at 5:58 PM, Viktor Dukhovni
<cryptography at dukhovni.org> wrote:
> On Sat, Apr 12, 2014 at 04:43:35PM -0400, Kevin W. Wall wrote:
>
>> And with a bit more work, one could even extend this technique
>> to find and alter Strings that are declared 'private' within a
>> given class. You would just have to pass in an Object and the
>> name of the field you wanted to alter. (Left as an exercise for the
>> reader.)
>>
>>     public static void changeString(String original, String replacement)
>>     {
>>         try {
>>             Field value = String.class.getDeclaredField("value");
>>             value.setAccessible(true);
>>             value.set(original, replacement.toCharArray());
>>             Field count = String.class.getDeclaredField("count");
>>             count.setAccessible(true);
>>             count.set(original, replacement.length());
>>         } catch (Exception ex) {
>>             ; // ignore
>>         }
>>     }
>
> This is a profound failure to understand the kind mutability required
> to securely erase sensitive data from memory.  Just because one
> can mutate values seen by users of an object's interface, does NOT
> mean that the underlying memory has been overwritten.

I realize that. I also wasn't born yesterday. But given that I've
been hacking Java for more than 15 years and before that, C and C++
for 20+ years, I *do* understand the issue. There is no profound
failure to understand what is required to erase sensitive data from
memory on my part, but perhaps there is a failure on your part to fully
comprehend Java's reflection mechanism, how Java's String class is
implemented, and Java garbage collection interplays with all of this.
Or perhaps you were just too quick to judge me.

Either way, that's *exactly* what is going on here....the underlying
memory for the specific String object that is passed to changeString()
*is overwritten*. (The 'value' Field reference refers to the
'private final char value[];' member in the java.lang.String class.)

What I did not say--because I was assuming that Jerry and Ian and others
that were following along understood--is that this may not necessarily be
sufficient, depending on your context. I didn't address that because
that was not the question that I was addressing and I figured it was rather
obvious. Rather I was specifically addressing whether it was possible to
overwrite a supposely immutable Java String and in general the answer
to that is 'yes'.

That does NOT mean that using this technique is always sufficient to
clear sensitive data from memory and I never claimed that it was.
For instance, if you were doing this in a servlet context and you
ad code like this in your servlet (or the equivalent in a JSP,
which compiles into a servlet):

 public void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException
 {
      ...
      String user = request.getParameter("user");
      String password = request.getParameter("password");
      try {
        authNservice.authenticate(user, password);
      } catch(AuthenticationException ex) {
        ... handle failed authentication ...
      }
      finally {
        // Just an example for illustrative purposes
        changeString(password, "****************************************");
        password = null; // Make eligible for GC
      }
      ...
 }

That is NOT going to be sufficient to clear the password from memory.
It's clearly going to still be around in the HttpServletRequest obect
that was passed it. Now you _might_ be able track it down and overwrite it in
the same way (why I alluded that you could extend this class)
but in general, you don't know where else the password has been
copied and you are fighting a losing game. Plus the Java servlet model
is multi-threaded so you're probably also screwed in that sense as well.
And of course, in the meantime, the particular memory segment that
contained this user's plaintext password could have been paged out to
swap space, etc.  So, foolproof? Not bloody likely.  Sufficient? Probably
not, but it somewhat depends on your context. I would claim that for
some circumstances that are *completely* within your programmatic control
(which admittedly is relatively rare), you can in fact clean up. In a
way, Java's passes references rather than copies or copy-on-write
(which it doesn't do for Strings because it treats them as immutable)
can actually help you somewhat here. But to be successful in cleaning
up you also have to avoid classes like the Swing classes that Jerry
was referring to because God only knows what they do with it and how
many hidden copies they squirrel away.

You could also use JNI to take care of this to some extent, but that will
be very not portable. But these techniques work and I know because I've
done this under special circumstances and confirmed them by retrieving
the memory of the running process (under Linux and Solaris) and ran
strings(1) and even gdb(1) on them to make sure stuff was properly
sanitized. But doing it from within a JavaEE container, or even maybe
an applet, etc., and you're probably screwed. It's theoretically possible,
but probably not worth the effort. Frankly I doubt it could be done in
a portable way that works for all JavaEE containers across all operating
systems although I would love to have someone prove me wrong though so
that I could benefit from it.

-kevin
-- 
Blog: http://off-the-wall-security.blogspot.com/
NSA: All your crypto bit are belong to us.


More information about the cryptography mailing list