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!"Crypto is hard.