4 ms·
The key derivation function's purpose is to take a long time (CPU time) to compute an output key given a password input. The combination of dangers here is tha
by rarrrrrr 14y ago
The key derivation function's purpose is to take a long time (CPU time) to compute an output key given a password input. The combination of dangers here is that the KDF is too fast (doesn't take enough CPU) AND the output is the same per user.
What we're trying to protect against is someone in possession of the data (such as Mega themselves, or anyone working for them, or hacking them, or seizing their assets, or just someone over the internet making an offline attempt against an account after discovering the auth hash) from making a brute force attempt to learn the plaintext content of the accounts.
So to help me crack accounts, I could make a database of outputs from the KDF, with every password combination pre-computed. "Start with "aaaaaa" as a password, and go all the way through "ZZZZZZ" out to some number of characters. The database would have 32 output bytes per entry. The first 32 bytes would be the output of "aaaaaa" through the kdf, then "aaaaab", and so on.
If my math is right, going out to 6 characters using letters numbers and punctuation, the database (probably just a file really) would be about 5 TB in length, and based on my single slow CPU's AES speed, would take about 99 CPU days to compute. Of course if you have 100 CPUs (or EC2, or a botnet) you could have it done in time for dinner tomorrow. Or just wait because someone will likely precompute one you can bittorrent in the next few days.
So, if I wanted to make a brute force attack against Mega's database of users, I would use this pre-computed database, reading it sequentially from disk, taking every 32 byte section and trying it as a key to decrypt the next layer of keys for a user. My CPU could likely check answers faster than the data would stream in from the disk.
So I would be able to brute force any combination out to 6 password characters in a few minutes using only the spare hardware sitting around my office and unoptimized code. Imagine what NSA could do.
So, finally getting back to answering your question. If the salt were used, then I couldn't pre-compute the KDF output. I would have to do it separately for each user. So then my attempts would (again on my weak CPU) proceed at only about 520 attempts per second. That's still about 500 times to fast. So, the design needs both a slower KDF, and salt. :)
Trivia: Want to time your own CPU and how many AES cycles it can do?
$ openssl speed -evp aes-128-ecb
Doing aes-128-ecb for 3s on 16 size blocks: 102358287 aes-128-ecb's in 3.00s
>>> 102358287 / 3 / 2**16
520
Hopefully that makes sense!
- jules 14y agoWell it kinda does make sense but I don't understand why you would go through this trouble with sending salts around. If the goal is what you describe couldn't you just derive a salt from the username at the client side? (I was assuming that they were already doing this, but apparently they are not?)
- jfarmer 14y agoThe higher the entropy of the salt the better. Let's say everyone did as you propose and use usernames for salts. I could pre-compute dictionaries for usernames like root, admin, etc. and likely gain full access to a wide range of systems. Our aim is to build a system where brute-forcing is always the cheapest option. Once that's the case, we're in a position to control "how expensive" it is for someone to invert even one derived key.
- jules 14y agoPresumably each username on Mega is unique, so that precomputation won't give you anything.
- jiggy2011 14y agoPerhaps the point is to reduce the risk that a rainbow table already created for some other use could be used in this case?
- jules 14y agoThat would at most reduce the number of KDF calls an attacker would need to perform by a factor of 2, if (1) the other service is using exactly the same KDF (2) all the usernames are identical in the two services. If not all the usernames are identical, then the factor of 2 is even lower. If an attacker can perform n calls to a KDF then he can also perform 2n calls to it, so if you're relying on that factor of 2 for security you have a problem no matter what. In any case this is easily defeated by adding a random string: KDF(username + "|blablafoo|" + password).