[Cryptography] Heartbleed and fundamental crypto programming practices

Jerry Leichter leichter at lrw.com
Sun Apr 13 16:20:11 EDT 2014


On Apr 13, 2014, at 11:30 AM, Benjamin Kreuter <brk7bx at virginia.edu> wrote:
>> I happened to develop a system in C++, which is the only widely-used
>> language that offers *compiler enforced*, user-programmable,
>> cradle-to-grave control over memory allocation.
> It is also one of the few languages where this is of critical
> importance.
>> By putting the code to zero the memory into the destructor, I could
>> guarantee that no RedString could make it back to the free list without
>> being cleared.  There's no way to do that in any other language I know
>> of.
> Again, this is critical in C and C++ where you have no particular
> guarantees about memory safety....
>> That means you have to enforce the discipline yourself.
> 
> As opposed to all the discipline you must enforce by yourself in C++?....
Having gone back and forth between C++ and Java in different projects more than once, and having programmed in a variety of other languages over the years, I suppose I could get deeply into a debate about the flaws and merits of the two languages.  But you know what?  It's pointless and boring.

I do, however, want to correct one important error.  The inability to read stray junk left in memory is not, in general, covered by either the notion of type safety, or that of memory safety.  It's something Java adds by the way it defines the initialization process for all allocated objects:  They are guaranteed to contain type-specific constant values - in practice, to be zeroed before any user-written code (including a constructor!) could see them.  (The story is a bit more complicated for local variables, which need not be initialized - but the semantics of value assignment and propagation is carefully defined to guarantee a compilation error if code could read an uninitialized value.  I haven't looked closely to see if there are holes in this guarantee that a program could exploit.  I'd guess there are, but perhaps they aren't large enough to be significant.  I would also guess there are holes in some of the badly designed antique corners of the language like deserialization and the definition of clone(), both of which bypass all the constructors.)

There have been languages which are type- and memory-safe but do not clear memory.  A good example is Modula-3, from which Java drew many of its foundational ideas.  The guarantee in Modula-3 was simply that any uninitialized variable contained the proper representation of some arbitrary member of the value set of that variable's type.  Since any bit pattern in an integer field represents a legal integer value, no explicit initialization code was required.  (In practice, what this *mainly* ended up meaning was that variables of reference types were set to null pointers.)

One can argue the merits of an explicit initial value.  From a security point of view, it's certainly helpful - though a "security conscious" implementation might well chose to zero at deletion rather than at allocation, and perhaps zero local variables that can't be absolutely certain to be fully written before they are read.  Both are *permitted* by the definition of the language, but no required.
                                                        -- Jerry



More information about the cryptography mailing list