TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

There are no good constant-time data structures

43 pointsby dmitover 10 years ago

11 comments

tptacekover 10 years ago
I feel like I must be missing something here.<p>You do not need constant-time comparisons of password hashes; to see why, reason through how you&#x27;d attack them.<p>An attack against an HMAC authenticator provides full, incremental control over the hash. No such control exists for a password hash; you can&#x27;t step from &quot;AAAAAA&quot; to &quot;AAAAAB&quot; without a devastating break in the hash function itself. The capability to predict the input that generates &quot;AAAAAB&quot; implies a total failure of preimage resistance.<p>You <i>can</i> end up in a situation where timing leaks are relevant to password authentication. To do that, you need to design your own password storage system, and it needs to be badly flawed; for instance, you could literally use a general-purpose fast lookup hash and a chaining hash table. This is yet another reason to simply use bcrypt or scrypt to store passwords; doing so takes timing off the table.<p>In reality, though, you could just use a salted SHA1 hash (don&#x27;t, though) and still be safe from this attack.
评论 #8692058 未加载
评论 #8691550 未加载
评论 #8691524 未加载
thaumaturgyover 10 years ago
I don&#x27;t understand: why not write the function to take a predetermined (or even slightly random) amount of time to run, and have it just sleep at the end of execution until the timer&#x27;s up?
评论 #8691000 未加载
TheLoneWolflingover 10 years ago
&gt; a key-value map on common hardware that runs in constant time and is sublinear in the number of entries in the map<p>Counterexample: Cuckoo hashmap, at least for lookup.<p>Calculate both hashes. Index the table via each hash. Check both table indexes to see if either match.<p>The only timing information this leaks is the length of the input string, and that an adversary already knows.<p>Now, there will be some cache information potentially leaked, although there are ways around that too. But this is constant time disregarding cache, and is sublinear.<p>As for the question of &quot;a nice constant-time comparison algorithm for (say) 160-bit values&quot;, it&#x27;s relatively easy. Do a pairwise comparison of constant-size chunks of the value, mapping &lt;, =, and &gt; to 01, 10, and 11, respectively. Then recurse as necessary. Of course, this assumes you have a constant-time comparison function for a single chunk.
评论 #8691378 未加载
评论 #8690615 未加载
pbsdover 10 years ago
&gt; One problem is, I don&#x27;t know of a nice constant-time comparison algorithm for (say) 160-bit values. [...] I would appreciate any pointers to such a constant-time less-than algorithm.<p>The following should be constant-time relatively to the contents of its inputs:<p><pre><code> &#x2F;&#x2F; return -1 if x &lt; y, else 0 static unsigned lt(unsigned x, unsigned y) { return -((x - y) &gt;&gt; (sizeof(x)*8-1)); } &#x2F;&#x2F; return -1 if x != y, else 0 static unsigned ne(unsigned x, unsigned y) { const unsigned d = (x - y) | (y - x); return -(d &gt;&gt; (sizeof(d)*8-1)); } &#x2F;&#x2F; return 1 if x[0..n-1] is lexicographically less than y[0..n-1], else 0 int less_than(const unsigned char * x, const unsigned char * y, size_t n) { unsigned flag = 0; unsigned done = 0; for(size_t i = 0; i &lt; n; ++i) { flag |= lt(x[i], y[i]) &amp; ~done; done = ne(x[i], y[i]); } return flag &amp; 1; }</code></pre>
评论 #8691556 未加载
评论 #8692765 未加载
评论 #8691117 未加载
评论 #8691100 未加载
daveloyallover 10 years ago
<p><pre><code> &#x2F;&#x2F;quantize run duration to mitigate timing attacks checkPasswordWrapper(...) { result = checkPassword(...) until (getMilliseconds() % 250) { sleep(1) &#x2F;&#x2F;Needs optimization } return result }</code></pre>
kazinatorover 10 years ago
You can gate the completion of each hash lookup with an absolute-sleep, e.g. using the POSIX function clock_nanosleep with a flags value of TIMER_ABSTIME.<p>Before the hash lookup, calculate a set time into the future, say 300 ms. Then do the hash lookup. Then wait until the predetermined time and return the result.<p>Waking up a thread at a specific time is just real-time programming 101.<p>Another idea: if you have some context information that lets you identify that queries are coming from the same entity (same IP address, same tty, same operating system user, whatever), you can impose a shadow ban after 10 unsuccessful tries: fail even if there is a hash &quot;hit&quot;, and randomize the times to feed the attacker junk timing data.
评论 #8691653 未加载
Animatsover 10 years ago
One approach is to use a hash table where each entry has a block of values, not a linear list. The entire block is always tested linearly, even though most of the values are null. Block overflow means an expensive operation to increase the size of the hash table or the blocks, but that&#x27;s an insertion-time issue, not a lookup-time one.<p>There&#x27;s still the problem of cache noise.
TheCorehover 10 years ago
So, hash tables don&#x27;t really work like this. There&#x27;s no reason for the &quot;FOOBAR&quot; password to be stored close to &quot;FOOBAZ&quot;, if you pick a well behaved hash function. You might get to know how many passwords are on the same hash bucket, but that&#x27;s it. Furthermore, the authentication will be accessed over a network. The network latency (and it&#x27;s variance) is several orders of magnitude larger than the possible variations. It would be seriously hard to measure something like this with the resolution needed (nanoseconds). Even if you&#x27;re taking samples and doing an average based guess, you&#x27;d need an absurd number of samples (so a bruteforce attack on passwords would be more feasible?)<p>Edit: Actually, even if by coincidence you did get FOOBAZ on the same bucket as FOOBAR, you wouldn&#x27;t be able to easily distinguish from a single comparison with 5 equal characters from multiple comparisons with smaller number of equal characters. Also, if you&#x27;re getting that many collisions to the point that this is a problem, you&#x27;ve sized your hash table incorrectly.
sjmover 10 years ago
For the problem mentioned in the post (determining whether a given password is valid), how about using a Trie[0]? Wouldn&#x27;t this work perfectly in this situation?<p>[0]: <a href="http://en.wikipedia.org/wiki/Trie" rel="nofollow">http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Trie</a>
评论 #8691751 未加载
daveloyallover 10 years ago
I&#x27;m embarrassed to admit that I thought &quot;timing attacks&quot; had something to do with race condition bugs. ...Crap, I&#x27;ve got some reading to catch up on.
masoniumover 10 years ago
Or, ...add sleep(rand(..)) to each lookup, regardless of result.
评论 #8690690 未加载
评论 #8690709 未加载