9 ms·
There might be a chance of timing attacks against such "security". A secure system should never depend on obscurity.
by fdomig 11y ago
There might be a chance of timing attacks against such "security". A secure system should never depend on obscurity.
- trebor 11y agoIt's also pretty sad that they didn't use a constant time comparison function. Whether it exists in the target language standard library or not, it's easy enough to write one.
- muaddirac 11y agoWanted to add that as of 3.3, Python has a nice constant-time compare built in: https://docs.python.org/3/library/hmac.html#hmac.compare_digest https://docs.python.org/3/library/hmac.html#hmac.compare_dig...
- d0vs 11y ago2.7 actually https://docs.python.org/2.7/library/hmac.html#hmac.compare_digest https://docs.python.org/2.7/library/hmac.html#hmac.compare_d...
- jdhawk 11y agoIt looks like they're including and checking a timestamp with the payload. Is this not sufficient?
- trebor 11y agoNo. A timing attack is used to determine the shared key that creates the HMAC. Because == and === (depending on the language) use memcmp(), the time of the comparison varies. EG: 36D5F4EA999342FED17D7488CB260FC92926 36D5F4EA999342FED18D7488CB260FC92926 The code would compare only up to the difference and return, indicating through the time spent analyzing the HMAC how many characters are the same. The attacker can then work the HMAC like they would a combination lock, till they reproduce the key used. That's why a constant time comparison is so important: it leaks far less information.
- sdevlin 11y agoThis is a forgery attack, not a key-recovery attack.
- trebor 11y agoI am not a cryptographer. I don't quite understand the distinction you are drawing with so little information. Care to explain what I misunderstood?
- sdevlin 11y agoGiven a message M and a secret key K, we have: MAC(K, M) -> T To validate a pair (M, T), we verify: T = MAC(K, M) Ideally, the execution time in this verification is independent of T. But many languages use string-comparison algorithms that exit immediately on failure. If Eve can detect this difference with high granularity, she has an oracle telling her how many leading bytes of a guessed tag T' are valid: O(M, T') -> n She can use this to recover the first byte of a valid tag for M: for k in [0, 255]: if O(M, k || 0000...) > 0: return k She can extend this to recover the second byte, the third, and so on. Eventually, Eve will recover T such that MAC(K, M) = T. In other words, Eve is able to forge an authentication tag T for an arbitrary message M. What she won't do is recover K. So while she can forge tags for arbitrary messages, each forgery will require a fresh, online interaction with the verifying party. She cannot work backwards from (M, T) to K.
- sarciszewski 11y agoTo put it another way: You (slowly and painstakingly) defeat the authentication without having to brute force, e.g. 2^128, possible keys. However, the key is still unknown to you. It just doesn't matter, because you can forge messages without it.
- trebor 11y agoThank you for the in-depth explanation!
- 11y ago
- sarciszewski 11y agoNode.js example: return new Buffer(sig).toString('base64') == signature; PHP example: return hash_hmac("sha512", $string_to_verify, $shared_secret) == $signature; Yeah, like fdomig said: timing attacks. The Python example included a mitigation. PHP includes hash_equals() and a constant time comparison in Javascript isn't difficult to write. Possibly also, the Ruby example: return OpenSSL::HMAC.digest('sha512', shared_secret, string_to_verify) == signature (I don't write Ruby so I don't know if this is overloadable somewhere.)
- deleted 11y ago[deleted]
- beefhash 11y ago> (I don't write Ruby so I don't know if this is overloadable somewhere.) Ruby allows overriding the == operator[1], but OpenSSL::HMAC.digest returns an instance of String[2], rather than returning a special subclass of string or some other kind of special HMAC-representing class overloading ==. [1] http://docs.ruby-lang.org/en/2.2.0/syntax/methods_rdoc.html#label-Method+Names http://docs.ruby-lang.org/en/2.2.0/syntax/methods_rdoc.html#... [2] http://ruby-doc.org/stdlib-2.0.0/libdoc/openssl/rdoc/OpenSSL/HMAC.html#method-c-digest http://ruby-doc.org/stdlib-2.0.0/libdoc/openssl/rdoc/OpenSSL...
- vidarh 11y agoTo be pedantic, in Ruby, the fact that an object is of class String is not sufficient evidence that a method has not been overloaded (they can be overloaded via the objects eigenclass), though you're probably right.
- Freaky 11y agoEven if it did (and it doesn't, I checked), you're probably still better off doing it explicitly since it's easier to audit, less likely to differ across implementations, and less error prone (e.g. swap the order of the comparison and you're back to plain old String#==).
- 11y ago
- tantalic 11y agoAll crypto libraries should provide and developers should use constant time comparisons for exactly this purpose. A good example from the same page is the Go crypto/hmac package includes mac.Equal to check for equality without introducing timing weaknesses.