It's probably worth pointing out: you have the same problems if you're using CFB, OFB, or CTR mode (these are the "stream cipher" modes for DES/AES/whatever that encrypt one byte at a time). There's apocrypha about these modes not being vulnerable to the attack. Bad apocrypha:<p>Set up an encryptor:<p><pre><code> irb> e = OpenSSL::Cipher::Cipher.new('aes-256-ofb')
=> #<OpenSSL::Cipher::Cipher:0x647100>
irb> e.key = "\x11" * 32
irb> e.iv = "\x00" * 16
</code></pre>
A decryptor:<p><pre><code> irb> d = OpenSSL::Cipher::Cipher.new('aes-256-ofb')
=> #<OpenSSL::Cipher::Cipher:0x647120>
irb> d.decrypt
irb> d.key = "\x11" * 32
irb> d.iv = "\x00" * 16
</code></pre>
Encrypt something:<p><pre><code> irb> ciphertext = (e << "A * 40")
=> "a\255N\211XEn\001\347$\275)\311%Ht\2356\254m\b\234z\375\311\006\335\305F\231~\201\243\236\3628w\267\3454"
</code></pre>
Make an XOR mask:<p><pre><code> irb> mask = ("187 she wrote".to_bignum ^ ("A" * 13).to_bignum).to_rawstring
=> "pyva2)$a63.5$"
</code></pre>
XOR it into the ciphertext:<p><pre><code> irb> new_ciphertext = (ciphertext.to_bignum ^ mask.to_bignum).to_rawstring
</code></pre>
NOW decrypt it:<p><pre><code> irb> d << nct
=> "AAAAAAAAAAAAAAAAAAAAAAAAAAA187 she wrote"</code></pre>
I didn't buy the GPG/TLS thing before. After reading this I do. I just realized how completely out of my depth I am for crypto stuff. At least now I know ...
Great post! I'd love to see more of this kind of thing; approachable explanations of the right way to do security and how easy it is to do it wrong.<p>Unfortunately, there's seems to be a <i>huge</i> gap between the average working programmer, who often has little idea how to do security, and the security guru's who are often barely intelligible to the rest of us. :-)<p>Sadly, the result of most programmer's poor understanding of security is even worse than the bad crypto implementation in the article. It's often something as basic as thinking it's O.K. to store user passwords un-hashed. (<a href="http://news.ycombinator.com/item?id=628680" rel="nofollow">http://news.ycombinator.com/item?id=628680</a>)
Is there a shorthand name for "the industry standard answer; the cookie both apps honor to let you in, encrypted so users can’t change their account to someone else’s" pattern, especially that pattern 'done right'?<p>What's the best battle-tested library (and call) for implementing exactly that, without making any of the common mistakes?
I would just like to point out that in 13 hours nobody has posted a comment here that even bothered me a little, whereas it took less than 3 hours for Reddit to bust out the one-time pads.
Thanks, Thomas. I just finished implementing my own crypto in a webapp I am working on. (AES, with Diffie Hellman for a shared secret we needed)<p>You've made me so nervous about everything I thought was true that I did a hg revert and am looking at gpgme bindings.<p>You've done a good deed, I think.
Good read. +1 for Louis CK reference.<p>A question to start up founders: How do you guys handle security? Do you hire consultants/pen-testers? Do you just copy+paste code from the internet? Do you use whatever framework's components for it?
<i>A “young, cool-people’s” coffee shop on the first floor of an old office building in downtown Chicago.</i><p>A place like this exists? All I can think of is Intelligensia.
It seems kind of silly to write one's own code for anything, if you have access to a well-tested library that does what you want. The only reason to do otherwise is where there is no such library. Crypto is just an example of an area that's particularly hard to get right: the solution is no different than for other things.
It was a nice read, but the screenplay delivery added a lot of confusion that I felt detracted from the point of the actual message. Maybe if it hadn't been so fragmented. Still, educational, though moderately confusing.
Isn't the whole problem in this situation that you are trusting the client with critical data? He takes possession of it, has unlimited time and opportunity to work on it, and successful falsification will be obvious for him? Why on earth trust the client with the data in the first place? I have never liked the "encrypted cookie" way of handling session storage.<p>Just have a server side session store and all of this cookie encryption crap just vanishes. Of course that won't help you with session fixation etc, but the post doesn't address that stuff either. Do it over TLS and you're pretty safe though.<p>And let's not forget the author's suggestion to pad out the cookie with 1000 bytes to make it harder to falsify. That cookie gets send with every single request. 20 images on the page, you're sending 20KB of junk up just to load the page. On a connection with slow upstream, like say ADSL, you can easily add a second or two of request latency. You might not care but some people sure do.<p>And come on, I read until the very end expecting to hear what "processes or threads" have to do with security, so tell us already!
So, is there much to be gained from encryption anyway? If, as the candidate, I suggested sending a cookie as 'userId=39493&role=user&timestamp=1414919&hash=<sha256-of-key-with-data>' then would I lose brownie points?<p>I assume my hash comparison function is constant time (eg. XOR(a[x],b[x])==0), rather than comparing of char-by-char.
I always try to espouse the benefits of triple-rot13 as the cipher in interview questions about security. Key management is a breeze, for example, and it's VERY fast.<p>But it allows everyone to concentrate on how you're managing the secure context instead of what algorithm has been shown to cause cancer in rats.
I don't understand what's so hard about encryption. There are simple, well-known rules (except the timing one that is sort of news), and if you follow them you should be safe, no?<p>1. Use a blocks-size unique prefix (IV) for each message (random will do as well)<p>2. SHA-256 your entire message before encryption and add the hash value at the end to prevent tampering<p>3. Use AES-256 with chaining to encrypt<p>4. Use SHA-256 to turn a password into a key.
If your key space is small harden it with hashing 1000 times or so.<p>5. The time your algorithm takes should be always the same (or at worst one time for success and one for failure)<p>6. Don't use any other symmteric crypto algorithm.
Great post, not that I can claim to understand all of it. One question:<p><i>Just put a “for” loop around SHA-1 and run it 1000 times to generate the key; that’ll at least slow down a brute force attack. SHA-1 is lightning fast. By itself, it’s a crappy way to generate a key.</i><p>I see the purpose of this, but doesn't it also provide 999 more opportunities for a hash collision to happen? Are you so confident in the collision resistance of SHA-1 that this isn't an issue?<p>My (probably naive) proposal would be to keep the result of the first hash and XOR it with the result of each subsequent hash. Bad idea?
Related to this: <a href="http://www.codinghorror.com/blog/archives/001267.html" rel="nofollow">http://www.codinghorror.com/blog/archives/001267.html</a> I assume.