- 130comments
- 3comments
- 10comments
- 192comments
- 41comments
- 172comments
- 2comments
- 25comments
- 59comments
- 409comments
- —discuss
- 89comments
- 40comments
- 53comments
- 158comments
- 637comments
- 28comments
- 3comments
- 264comments
- 99comments
- 177comments
- 86comments
- 10comments
- 240comments
- 55comments
- 163comments
- 168comments
- —discuss
- 25comments
- 31comments
This is from 2009.
And everything I said five years ago is still true! I'm proud of how well those recommendations have stood the test of time.
The past 5 years have not aged your aversion to elliptic curves very well. New modern designs by crypto specialists tend to be curve based. Curves also have a nice property in practice of tilting designs towards forward secrecy.
Naturally, we agree that devs shouldn't implement curves themselves --- but then, neither should they implement RSA-PSS. The right answer is to use Nacl, which is curve-based, but who cares? You're not interacting with that level of the design.
The past 5 years have not aged your aversion to elliptic curves very well. New modern designs by crypto specialists tend to be curve based.
The first of those statements does not follow from the second. I agree that there has been an increase in the usage of elliptic curves; but I've also seen a lot more attacks on elliptic curves recently than on RSA or DH(Z_p). Unless you have a particular need for small signatures (e.g., bitcoin) or maximal performance, I maintain that using elliptic curves is an unnecessary risk.
Curves also have a nice property in practice of tilting designs towards forward secrecy.
I'm not sure why you say this. DH has exactly the same PFS properties regardless of the group being used.
Reverse order:
My claim about forward secrecy is easy to understand: ECC software doesn't encrypt directly, but RSA software easily can, and developers (for instance: Paul Kocher) give in to the temptation to use RSA encryption directly. RSA practically begs developers to create systems that aren't forward secure.
There is a lot of new attack research on ECC. But how much of that research implicates (a) common implementations of (b) the popular curves (NIST-Px, secpx, and Curve25519)? Inquiring minds, who have been implementing a lot of attack papers on artificially vulnerable curve software, want to know!
(Also, curve attacks that target DSA tend to be the fault of the DSA construction. I'm guessing this isn't the level at which you're thinking of curves being attack in the literature, though.)
Wasn't there an ECC side channel attack in OpenSSL just a week or two ago?
As for the more theoretical research -- none of it has been relevant to widely deployed systems yet, but this is the nature of research. Elliptic curves have a lot of structure which is still being explored, and as long as people continue to find attacks against new variants, I'm not going to bet that they'll never find attacks against the widely deployed systems.
I put being wary of ECC right now in the same category as being wary of SHA256 in 2006. It's not broken but there's a worrying amount of progress on related systems.
Fair enough, it was the secpxk1 curves that were broken in OpenSSL --- although that was a DSA vulnerability! It relied on a partial nonce leak! You're right, but I declare my wrongness to be defensible in this case.
If you're referring to the recent FLUSH+RELOAD attacks, that is hardly ECC-specific. They also owned GnuPG's RSA earlier with the same technique [1]. On the other hand, if your argument is that ECC implementations are generally less mature, I can't disagree with that. I believe that ECC (using Edwards or Montgomery forms; debatable when using general Weierstrass form) is easier to get right with respect to solid implementations than RSA is.
With respect to theoretical attacks, it is of course impossible to know what the future brings. But as long as we're sticking with conservative prime fields, I think it's probably either going to be fine or all of ECC is dead. It's also not like integer factorization or discrete logs have reached some kind of complexity lower bound; it's certainly not impossible that we'll get a L(1/4) method in the future as well. I look forward to see how it plays out.
[1] http://eprint.iacr.org/2013/448
Since part of his argument is that it's especially easy to stumble into timing leaks with ECC implementations, it seems fair for him to call out OpenSSL's secp256k1 implementation.
It's also not like integer factorization or discrete logs have reached some kind of complexity lower bound; it's certainly not impossible that we'll get a L(1/4) method in the future as well.
Not impossible, no. But the fact that people have spent much longer looking for improved integer factorization attacks without making progress makes me more optimistic that integer factorization will continue to hold up to further scrutiny.
Can anyone explain why GCM is more attackable than CTR+HMAC? Is it because the signature is encoded in the ciphertext and can't be verified until some or all of the decryption occurs?
At the time this article was written, AEAD modes were apparently still too new, and their implementations too untrustworthy:
http://www.daemonology.net/blog/2009-06-24-encrypt-then-mac....
At the moment, the best-supported AEAD mode seems to be AES-GCM, which has received a fair bit of attention since then. Alternately, {Salsa20,ChaCha20}-Poly1305 has some good implementations, e.g.
http://nacl.cr.yp.to/
and in TLS:
https://www.imperialviolet.org/2014/02/27/tlssymmetriccrypto...
AEAD modes were apparently still too new, and their implementations too untrustworthy
Also, using Encrypt-then-MAC allows you to discard inauthentic messages without ever decrypting anything, which protects you from side channels in your block cipher.
It's bizarre that this is still something we have to worry about.
The argument I saw was that GCM is really hard to implement securely.
It's not, really, but the problem people are referring to is actually not too hard to explain.
An HMAC authenticator is conceptually very simple. You start with a secure hash (even MD5 still qualifies, barely, when we're talking about HMAC), and, given a "key" and a "message", apply the hash function twice: an inner hash of the key and the message, and an outer hash of the key and the inner hash (the inner and outer hashes are distinguished by an "inner pad" and "outer pad" constant). Doing this produces a secure message authenticator for a message assuming the hash and key is secure (with SHA3, you don't even need HMAC, and can create a secure authenticator out of a simple keyed hash).
You understand a secure hash, you understand what a keyed hash is (concatenate the key and the message and now only people who know the key can replicate that hash), and now you get what HMAC is.
GCM is CTR mode, like Colin says you should use with HMAC, plus a GHASH authenticator. GHASH is a little trickier to understand than HMAC, but you can get most of the way there by thinking of it as a thermonuclear CRC algorithm: it's (at root) polynomial multiplication and reduction.
The problem with GCM is that fast polynomial multiplication and reduction in software is table-driven. When software verifies a GHASH MAC, it is forced to look up elements in a table at locations determined by a secret. Those lookups end up configuring the system's cache; future memory references at addresses that collide with the secret table indices will be measurably faster than references that don't collide. Attackers can write software that profiles cache hits and from that information potentially recover secrets.
Modern implementations of GCM on X64 hardware get hardware-accelerated multiplication optimized for this operation, mitigating the table lookup problem. But GCM is still potentially a concern for platforms that don't have these instructions.
The plus side of GCM is that you'll never implement it yourself: it's gnarly enough that everyone uses one of a few library implementations of it. As a library interface, GCM is very nice: you're getting a "seal" and "unseal" operation that securely verifies authentication and then handles decryption, in the correct order of operations. On recent server hardware, that implementation is likely not to have side channel problems; the same is rarely true of HMAC implementations, which tend (annoyingly) to be hand-hacked, particularly for verification.
The "cool kids" replace GCM with Salsa20+Poly1305, which replaces AES-CTR with a native stream cipher (Salsa20, which is actually a hash core running in CTR mode) and a polynomial MAC that is very fast in secret-table-free software. If you use Nacl, that's what you're getting; it's something much closer to GCM than to AES-CTR+HMAC.
On recent server hardware, that implementation is likely not to have side channel problems; the same is rarely true of HMAC implementations, which tend (annoyingly) to be hand-hacked, particularly for verification.
Disagree. Hashes and HMACs are very safe against side channel attacks. Heck, I don't think I could insert a side channel if I tried!
On a 1-10 scale of side channel attackiness, hashes and HMACs are 0, block ciphers are 3-4, and asymmetric crypto is 6-8.
Come on. You mean apart from virtually every web stack's implementation of HMAC? They all start with a version that uses string comparison.
In case anyone is wondering the proper way to compare two HMACs, it's to xor the strings and check whether the result is zero. If string A xor string B is zero, then they're equal. If it's nonzero, then they're not equal. This will prevent timing attacks, because the entirety of both strings are compared.
When you compare the two HMACs using standard string comparison, you expose yourself to a timing attack because the algorithm will likely stop comparing after finding the first difference in the strings.
In case anyone is wondering the proper way to compare two HMACs, it's to xor the strings and check whether the result is zero
You've just punted the problem. How are you checking whether the result is zero?
The correct code (copy and paste from libcperciva):
Heh. My first answer was "copy paste the algorithm from tarsnap," but then I thought I'd better explain it directly. Thank you for pasting it.
Might it be even safer to squash 'rc' down to a single pair of values (0 or 1), rather than leaving the caller with the responsibility of testing a byte for zeroness safely? By leaking the 255 possible values for "not equal" to the caller, we're kind of punting the (smaller) problem, and they might do something nutty like add it to some other constant (incurring timing-leaking carries) before comparing the result against something.
Of course, we're not just defending against surprises from the calling code, we're defending against compiler behavior too. We're trying to constrain its options so tightly that it has no choice but to emit a series of machine instructions that we know will run in constant time. If it weren't such a hassle, we'd write crypto_verify_bytes() in x86 assembly.
It'd be lovely if our languages had a way to express these constraints directly, instead of phrasing them with artificially small types and low-level logical operations.
A question.
What prevents a compiler from optimizing that function to non-constant time? For example, by inserting a bailout condition (rc == 255) into the loop? (I am aware that it probably wouldn't, but "probably" in cryptographic contexts isn't generally good enough...)
Theoretically? Nothing at all. You could have a compiler which produces code which revs the CPU in such a way to output the complete works of Shakespeare in Morse code via the fluctuations in your laptop's fan speed, and it would be perfectly standard-compliant.
Worse than that, there's things compilers actually do in practice, like optimizing away
and you can't even protect yourself against that properly by using a (volatile *) cast since the compiler is perfectly within its rights to make extra copies of that data and even without optimization the memset will only zero one of the copies. (gcc in particular loves to copy data onto the stack, due to a broken register allocator.)
I've been trying to convince some clang developers that we need to have a C language extension for "we're handling sensitive data here, don't optimize it in dangerous ways", but it's difficult to define exactly what optimizations could be problematic...
Also, in interpreted languages, it's difficult to know whether the primitive operations actually are constant time, which is why I think the better universal solution is to hash both the MAC from the untrusted input as well as your own computed MAC once more with the same HMAC with a random key and only then do the comparison on the result of that. The HMAC should be constant time anyhow, and with this construction, it shouldn't matter much whether the final comparison is constant time.
Ok, but if people are going to get that wrong, they're going to get a million other things wrong too.
There's a reason I talk about this in my crypto-in-1-hour talk though. ;-)
Sure, but this is something you don't get wrong if you use a GCM library. It's like my take on ECC and forward-secrecy: you're right, it's not an intrinsic property of GCM that it avoids side channels (the opposite, even), but in practice it guides developers towards implementations that are less likely to have them.
If you reuse a nonce, even once, then any message can be forged with GCM. HMAC doesn't have this issue, but also doesn't handle nonces natively, which the confidentiality loss for both is the same. On devices which never reuse secret keys across power cycles this is probably not a problem, but it can be in some environments.
Colin recommends CTR+HMAC, which has exactly the same problem. I don't think that's what he's referring to.
They both have exactly the same confidentiality issue (because both use CTR mode) but the forgery issue is specific to GCM as a single successful forgery leads to infinitely many. With truncated tags this is a real issue. But with big tags both have pretty much the same "good for counting, terrible if you can't" behaviour.
I don't understand this part - if I'm not using SSL, what am I doing at this point?
Something e.g. SSH does. A simple encrypted connection without a big certificate stack.
Alone among these recommendations, this one is indefensible in practice (though understandable on paper). We see people implementing "simpler" TLS alternatives somewhat routinely in our practice, and they are virtually always broken. A fear of TLS --- which is reasonable --- is an insufficient reason to expose yourself to the risks of a custom crypto protocol.
You'll save yourself time and heartache if you just use SSL. Once every few years, someone will find a flaw in TLS, and once every few times that happens, that flaw will be relevant to your application. But on those rare occasions, you'll also have some of the smartest crypto implementors on the planet rushing to come up with the best fix, which is something you will never have with a custom protocol.
It is worth remembering here that the overwhelming majority of TLS security issues are relevant primarily to browsers, and rely on the BEAST exploit model, where attackers have extensive and fine-grained control over what plaintexts victims generate, due to Javascript.
If certificate processing code scares you --- also reasonable! --- and you're building a client/server backend system, do what enterprise software does: slurp the whole certificate into your code, fingerprint it with a hash, and verify it in a whitelist. Your TLS implementation will still verify the certificate, but you won't care; you'll rely on your whitelist for security instead.
My advice is IMO much simpler. Feel free to write your own crypto code that uses a SSL connection. It might not be secure on it's own, but in the small windows where SSL happens to be broken you have a little extra security and even if you just do XOR your still basically safe in the first place.
You can actually end up less secure by layering additional crypto inside of SSL, particularly if (as is likely, given what most people are afraid of in SSL) your crypto involves endpoint authentication.
What Colin wants to say in this document but couldn't at the time (because it didn't exist yet) and won't now (because of false modesty) is that he thinks you should use spiped instead of TLS. If he'd say that, I'd agree that was a reasonable choice.
Do you have an example where SSL would have been secure if they had not added some other encryption scheme that broke something?
Sure: more than one product has used SSL with SRP inside of it to replace the certificate auth, and ended up with auth bypass bugs because they didn't check parameters properly.
replace the certificate auth
From what your saying that SSL layer was not secure on it's own. Which is a valid concern, but not what I am talking about.
No, don't use spiped. As awesome as it is, spiped is symmetric -- it's designed for "I control two servers and want them to talk to each other securely", not for "I want to publish code which people can use to talk to my server".
I've been considering writing aspiped though.
NaCl? http://nacl.cr.yp.to/