22 April 2014

The recent discovery of the
goto fail
and
heartbleed
bugs has prompted some public discussion on a very important
topic: what advice should cryptologists give to implementors
who need to use crypto? What should they do? There are
three parts to the answer: don't invent things; use ordinary
care; and take special care around crypto code.

Don't invent things

This oldest piece of advice on the subject is still sound;
everyone who teaches or writes on the subject will repeat it.
Never invent your own primitives or protocols.
Cryptographic protocols are fiendishly difficult to get
right; even pros often get them wrong. Encryption algorithms
are even harder to design.
It's certainly true that there have been very few known attacks
on bad crypto by hackers not working for a major government.
But "few" is not the same as "none"—think of WEP—and
many commercial sites have been targeted by governments.
Besides, many crypto attacks are silent; the victims may
never know what happened.

Custom crypto: just say no.

Use ordinary care

Crypto code is code, and is therefore susceptible to
all the natural shocks that code is heir to.
All the usual advice—watch out for buffer overflows,
avoid integer overflows, and so on—applies here;
crypto code is almost by definition security-sensitive.
There's no shortage of advice and tools; most of this is
even correct.

Special care

Crypto code, though, is special; there are precautions
that need to be taken that are irrelevant anywhere else.
Consider things like timing attacks: if you're
using RSA but haven't implemented it with all due paranoia,
an attacker can recover your private key just by seeing how
long it takes you to respond to certain messages.
There are cache timing attacks: if the attacker
can run programs on the same computer as your crypto code
(and this isn't a preposterous notion in a world of cloud computing),
it's possible to figure out an AES key by watching what cache
lines are busy during an encryption or decryption operation.
Alternatively, consider how hard it is to implement obvious
advice like zeroing out keys after they're used: if you write
code to assign zeros to a variable you'll never use again,
a modern compiler can optimize that code out of existence.
The problems are subtle and there aren't widely-known
sources of advice.

Nine years ago, Dan Boneh commented to me that
"It's amazing how tricky it is to implement
Crypto correctly these days. I constantly tell my undergrad
students that they should not try to implement existing
systems themselves."
It's even more true today.

Some of these issues can be dealt with by sticking with a well-implemented,
standards-adhering crypto library. Yes, there have been problems of
late with several different such libraries—but most programmers
will make at least as many mistakes on their own. Are we putting all
of our eggs in one basket and exacerbating the
monoculture problem? In this case, I prefer to fall back on
Pudd'nhead
Wilson's advice
here:

Behold, the fool saith, "Put not all thine eggs in the one
basket"—which is but a manner of saying, "Scatter your
money and your attention"; but the wise man saith, "Put
all your eggs in the one basket and—WATCH THAT BASKET!"