First, I'll quibble with some of these recommendations --- even though Colin (and Alex Ross, and probably Bruce) is more qualified to have an opinion here.
For instance, CTR+HMAC is a weird recommendation. Not because of speed (though HMAC does pessimize speed) and not because of cryptographic strength, but because it introduces another moving part in your design. Colin can deal with the junction between plaintext, ciphertext, and HMAC, because this is mostly all he thinks about. You can't.
A simpler recommendation would have been to use CCM or EAX mode. These have the advantages of being NIST standards-tracked and heavily vetted, and of providing both authentication and encryption in the same construction. If your libraries are good, you get both these features just by switching the name of your block mode.
Second, I'll quibble with the content of the post: these recommendations are exactly what Nate was talking about in his Yahoo talk about how bad cryptographic guidance has gotten. Key size and hash function selection (as long as you're not using MD5) are the least important design considerations you have.
Here's a design consideration this post doesn't even touch on: renewability. How do you safely design a system so that your selection of algorithms, modes, and key sizes isn't set in stone? Because if you don't get that right today, what you inevitably do to handle it 2 years from now is going to be a vulnerability.
Finally, a real concern about the structure of these recommendations: telling people to keep group negotiation out of Diffie-Hellman protocols is fine --- a good recommendation, since there's a really scary sounding, really easily-exploitable vulnerability that eliminates. But that's --- I think --- the only place in this post where Colin actually addresses something that actually does go wrong in crypto protocols.
If you follow all of Colin's recommendations here from scratch in a reasonably complicated, and you have never found a crypto vulnerability or fixed two reported crypto vulnerabilities, I will bet $500 that you end up with a broken system. Colin won't. But you will.
Encrypt-then-HMAC has been a widely used standard for the past decade, and has been extensively studied.
A simpler recommendation would have been to use CCM or EAX mode.
AES-CTR and HMAC-SHA256 are far more simple than AES-CCM or AES-EAX. AES-CTR plus HMAC-SHA256 is also far more secure against side channel attacks, and has the advantage of allowing you to separate authentication from encryption -- useful if, say, you want to include some unencrypted data in an authenticated packet as well.
Key size and hash function selection (as long as you're not using MD5) are the least important design considerations you have.
I didn't mean to imply that all of the issues I mentioned were very important. My selection was more or less done on the basis of "what questions have people asked me recently?"
If you follow all of Colin's recommendations here from scratch in a reasonably complicated, and you have never found a crypto vulnerability or fixed two reported crypto vulnerabilities, I will bet $500 that you end up with a broken system.
That's probably a safe bet. I think it would be an even safer bet if you made it with someone who didn't follow my recommendations.
Your first point, about how well-studied HMAC is vs. CCM, is one of those points that makes a lot of sense in an academic context and much less sense in practice. In an academic context you assume both implementations are sound. In a practical context, you have to consider how likely it is that the implementor is going to make unsound choices.
The same goes double for your second point. Yes, if you have to implement the MAC yourself, you clearly want to use HMAC rather than trying to get CBC-MAC right. But if you're in a place where you have to implement your own MAC, you are doomed for a bunch of other reasons. CCM is preferable to HMAC because it's likely you're going to simply be able to change CTR to CCM and have it.
I didn't say anything about implementing the MAC yourself. Someone has to implement it, though -- and no matter who writes the code, HMAC-SHA256 is far more likely to be right and not leaking data via side channels than CBC-MAC is.
Bespoke CBC-MAC is an almost-certain disaster. HMAC-SHA256 has some obvious implementation failure modes. It's less easy to see how someone screws up typing "CCM" into their library.
The point is that there are already shrink-wrapped AE constructions (like CCM or EAX) that you can pick up off the shelf and use; HMAC designs are more likely to be bespoke.
It's less easy to see how someone screws up typing "CCM" into their library.
If you trust the library, sure. But I've found that the same rules apply to crypto libraries as to everything else: Obscure and complicated features are far more likely to be buggy.
No crypto library is ever going to ship with a broken HMAC-SHA256 -- but I can't say the same thing about AES-CCM.
Seriously, Colin? You're talking about people that don't know to use AES-256 instead of Blowfish, but do know enough to homebrew instead of using a library?
CCM and EAX aren't obscure. AE crypto has been in 3 of the last 4 designs I've had to review. The fourth prompted a recent blog post of mine.
I'm with you on CTR mode: it's a uniquely dangerous recommendation to anyone who needs to be soliciting recommendations in the first place. If you're encrypting a file, then the obvious, elegant thing to do is to use position in the file as your counter. But then the moment you encrypt two files using the same key, you're screwed: you've just committed the equivalent of reusing a one-time pad. I feel like ever mentioning CTR mode to a novice without bringing this up is like inviting a guest into your house and forgetting to mention that you've rigged the door handle to explode if you turn it in the wrong direction.
I'm actually not anti-CTR mode; my recommendation (use EAX mode) has basically the same problem --- EAX is just CTR + OMAC.
You're right that stream ciphers blow up more spectacularly than block encryption does. You have to be sure not to re-use anything (counters, nonces, keys, etc). If "don't overfill a buffer" is an easy prescription that cost industry $4+bn USD, it's hard to imagine how unlikely it is people can avoid screwing up "don't reuse anything".
On the other hand, differentiatable errors cause spectacular problems with block encryption. See: the "bad padding" error message that decrypts entire AES blocks a byte at a time.
This depends on how small your embedded systems are. If your system is too small to run RSA, it's probably too small to use any asymmetric crypto; and if it's too small to use HMAC-SHA256, it's probably too small to use any crypto at all.
There are certainly applications where I would revise my recommendations, but embedded isn't particularly one of them.
I don't think that's quite right. The systems you're thinking of are almost certainly not too small to use RSA -- rather, they're too slow to use RSA. As I wrote in the article, ECC has advantages where speed is an important consideration.
I've definitely heard both objections --- space and time --- but my real point is, one of the app domains that most commonly hosts bespoke cryptography is largely incompatible with your recommendations.
This was largely inspired by Thomas's blog post yesterday about AES vs. RC4 -- he started me thinking "gee, someone really should sit down and tell people what they should be using so that they don't keep doing dumb things like using RC4".
Possibly truly stupid question, but what is the attack on md5ing passwords if you also generate a random salt for each user? I could not find anything online in the past ten minutes that suggests an attack, except for the md5 collision problem.
I don't understand the collision problem very well either. I know it's been used to crack a certificate here or there, but it seems like it took a lot of resources to crack one password.
"Client-server application security: Distribute the server's public RSA key with the client code, and do not use SSL."
It seems like the point of this is to make sure that when communication moves from the client, only the server with the proper private key can decrypt it - BUT, aren't you just going to use OpenSSL to implement this (via TLS)? Is there some other way to accomplish this I'm not aware of? What's he specifically warning us against?
I'm warning you against using a complex and error-prone protocol where you don't need all the complexity. You might end up using OpenSSL anyway, but using OpenSSL to perform an RSA encryption is vastly safer than using OpenSSL to verify a certificate chain.
I am a bit mystified by you warning people off SSL. It's complex because the problem of establishing a trusted channel between two unrelated parties is complex. Simpler protocols with the same constraints have failed.
You should be clearer with your recommendation. If you can relax the constraint that the protocol has to work between strangers, then SSL offers functionality you don't need, and the actual interface to SSL has moving parts that might hurt you.
Most people who build crypto can't relax that constraint, even if they think they can. We've beat several schemes that relied on pre-distributed public keys because of the out-of-band channels that wound up getting grafted on to bring new members into the group.
Finally, verifying a certificate chain isn't hard. It's constructing a verifiable certificate chain in the first place that has proven difficult. If IE7 didn't offer the "bad certificate" click-through warning, and simply failed the request, we'd be discussing the right problem instead of the red herring.
You should be clearer with your recommendation. If you can relax the constraint that the protocol has to work between strangers, then SSL offers functionality you don't need, and the actual interface to SSL has moving parts that might hurt you.
I specifically mentioned client-server applications, didn't I? If you are handing out client code which talks to a server you run, you don't need the protocol to work between strangers.
You need a secure way of handing out client code, sure. There's no way to get around that. But once you've figured out how to do that, you might as well include the server public key.
If an attacker can mangle the server public key which you're distributing with the client code, they can mangle the client code, at which point you've already lost.
So you draw an imaginary line around the parts of your application that have simple security requirements, make recommendations about the stuff inside the lines, ignore the stuff outside the lines, and berate the technologies that deal with the stuff outside the lines.
This is all the more critical when you consider how the usual web developer handles the complexities of chained certificate verification: namely, by disabling verification entirely, and instead trusting every upstream certificate as offered.
For example, as of Rails 2.3, ActiveResource (the default RESTful web service API client used in many Rails applications) disables all SSL verification whenever SSL is used, without so much as a configuration flag to enable it again.
This is a meme that needs to die. Users of SSL routinely fall into behavior traps that ruin the security of SSL. That doesn't leave them secure: it leaves them screwed. The problem that SSL is solving (and that applications are failing to solve) is hard.
If you can establish relationships between members of your protocol, you can rely on continuity for security. Continuity is what SSH uses. It's easier than authority, and it's sane to recommend that people take advantage of it when possible.
But when your users will constantly be enrolling new participants into your system, continuity becomes a huge design risk, just like how everyone used to lose their SSH keys to sniffers at Usenix Security.
This comment went a little over my head - if you don't mind, can you point me to something that explains what continuity and authority are in this context? I'm also curious to learn how people used to lose their SSH keys because of continuity. Thanks.
I'm concerned about the lack of revocation that comes with bundling a key in source. Shouldn't you warn people in your note that if the key is compromised, you're going to have a difficult time?
You should already have a mechanism in place for alerting people to vulnerabilities in your client code -- for all practical purposes, a compromised server key is just a vulnerability in the client code which needs to be corrected by upgrading to a newer version of the client.
If you're trained and experienced, there is probably nothing about performing standard appendectomy to challenge the intellect. But you're crazy if you think that optimism about human intelligence is enough to allow an ordinary smart person --- or maybe even an ER nurse --- to conduct one based on a guidebook.
There are things to be learned from the article at more levels than just the design of new protocols. For example, I would say this good advice that applies to ordinary smart people:
"Do NOT store users' passwords. Do NOT hash them with MD5. Use a real key derivation algorithm. PBKDF2 is the most official standard; but scrypt is stronger.
Please keep in mind that even if YOUR application isn't particularly sensitive, your users are probably re-using passwords which they have used on other, more sensitive, websites -- so if you screw up how you store your users' passwords, you might end up doing them a lot of harm."
For instance, CTR+HMAC is a weird recommendation. Not because of speed (though HMAC does pessimize speed) and not because of cryptographic strength, but because it introduces another moving part in your design. Colin can deal with the junction between plaintext, ciphertext, and HMAC, because this is mostly all he thinks about. You can't.
A simpler recommendation would have been to use CCM or EAX mode. These have the advantages of being NIST standards-tracked and heavily vetted, and of providing both authentication and encryption in the same construction. If your libraries are good, you get both these features just by switching the name of your block mode.
Second, I'll quibble with the content of the post: these recommendations are exactly what Nate was talking about in his Yahoo talk about how bad cryptographic guidance has gotten. Key size and hash function selection (as long as you're not using MD5) are the least important design considerations you have.
Here's a design consideration this post doesn't even touch on: renewability. How do you safely design a system so that your selection of algorithms, modes, and key sizes isn't set in stone? Because if you don't get that right today, what you inevitably do to handle it 2 years from now is going to be a vulnerability.
Finally, a real concern about the structure of these recommendations: telling people to keep group negotiation out of Diffie-Hellman protocols is fine --- a good recommendation, since there's a really scary sounding, really easily-exploitable vulnerability that eliminates. But that's --- I think --- the only place in this post where Colin actually addresses something that actually does go wrong in crypto protocols.
If you follow all of Colin's recommendations here from scratch in a reasonably complicated, and you have never found a crypto vulnerability or fixed two reported crypto vulnerabilities, I will bet $500 that you end up with a broken system. Colin won't. But you will.