I found this presentation how Facebook stores customer passwords and how they do authentication.

This slide shows how they hash passwords:

enter image description here

Is it a good idea to do such operations with a raw password? Isn't it "security-by-obscurity"? Does it make sense to do such operations with PBKDF2 as we're going to use?

  • 2
    Why do you think it's security through obscurity? They are implementing hashing & salting. It's the industry best practice for password storage. MD5 and SHA1 are cryptographically weak (given modern computing), but this is also from 2014, so I'm not sure if they are still using those algorithms (I'd be surprised).
    – HashHazard
    Mar 16, 2018 at 17:34
  • I'm asking if something like it makes sense now in 2018. We're going to use PBKDF2 HMAC-SHA256 with 8bytes salt, we're discussing what hashing schema use.
    – Artegon
    Mar 16, 2018 at 17:40
  • 1
    I'm confused about what your question is. Can you restate it?
    – schroeder
    Mar 16, 2018 at 17:50
  • 1
    what operation on a raw password are you talking about?
    – dandavis
    Mar 16, 2018 at 23:25
  • 2
    @eckes PBKDF2 is not faster as they both have configurable hardness. The real difference is that PBKDF2 is not memory-hard, whereas scrypt is.
    – forest
    Mar 17, 2018 at 1:03

3 Answers 3


In one of the comments you wrote:

I'm asking if something like it makes sense now in 2018. We're going to use PBKDF2 HMAC-SHA-256 with 8 bytes salt, we're discussing what hashing schema use.

The answer to that is no. The only part that should be replicated from the FaceBook solution is using a memory-hard function and the cryptoservice peppering. The MD5 and HMAC parts don't add to security. (They are fairly harmless though.)

You should not be using PBKDF2. In order you should prefer:

  1. Using a binding to the official native optimized implementation of Argon2
    • Refer to the Argon2 spec's "Recommended parameters" section for how to choose parameters.
    • The choice between Argon2d, Argon2i, and Argon2id may be up for debate. The current official recommendation is Argon2i for people that don't know which one to choose.
  2. Update your software so you can choose 1
  3. Protecting encrypted data using a password and can't use Argon2? Use a binding to a native optimized scrypt implementation. Set the single cost parameter high enough to use a lot of RAM and time. If it seems safe to reduce the time scrypt runs then reconsider. That also reduces the RAM-based cost.
  4. Protecting a few passwords, can't use Argon2, and can tolerate slow responses? Use scrypt with the same cost parameters as 4. If you're trying to protect admin accounts then prioritize using very strong passwords and encryption first.
  5. Protecting many users' account passwords and can't use Argon2? Use a library that uses a binding to native optimized bcrypt. Make sure the library correctly works around all of the original bcrypt algorithm's quirks. (The password will get truncated if it's too long or contains a null character.)
  6. Use a binding to native optimized PBKDF2. Don't use a derived key length greater than the underlying hash function's output length.
  7. Don't implement your own password hashing function. And especially don't run that implementation in an interpreter where it will be much slower. Update!

As for whether the FaceBook method is security by obscurity. No. But the HMAC parts and probably the MD5 part are redundant. The cryptoservice part probably uses an HSM. This should allow password hashes to be encrypted/decrypted without necessarily exposing the encryption key to the type of hackers that can steal a password-hash-database. Using mainstream encryption algorithms with a secret key does not count as obscurity. The password still needs to be hashed in case the key is ever leaked. That's what scrypt is for, but now Argon2 should be preferred.

Edit: See comments. As presented in the slide, the password does not get encrypted. HMAC is one way, just like hashing. The alternative of encrypting after hashing is useful because it allows the key to be replaced. Users need to enter their password if you change the key with this FaceBook setup, in addition to the salt or scrypt parameters. If you encrypt the hash then you can decrypt and re-encrypt it without requiring the user to enter their password. (If your key is ever leaked... But you can't rehash a password without the original.)

Also use 20 bytes of salt. Or at least 16.

  • Aside: I scrapped a post where I explained why the redundant steps were not harmful. And why the other steps were needed. I was also going to speculate why the were there, too. @eckes speculation that MD5 was part of client side hashing is reasonable. But client side hashing with a fast hash isn't useful for anything besides maybe side-channel related defenses. Aug 22, 2018 at 21:55
  • HMAC is not encryption, but besides that good answer! Aug 22, 2018 at 21:59
  • @AndrolGenhald Oops! That mix up is a huge pet peeve of mine. (Actually it's probably justified as quite a serious misconception.) I was working from memory and didn't notice HMAC in the line just before the red one. FB did use HMAC, but the should have use encrypt(secret, scrypt(password, salt)). That way keys can be replaced without users entering their password. (At which point it may as well be changed.) I remembered this slide and could have sworn they did it the second way. Aug 22, 2018 at 22:13
  • Just to be clear, you're suggesting encryption after scrypt/Argon2, whereas the slide shows an HMAC before scrypt, correct? Encryption before hashing wouldn't allow changing the key either. The benefit seems pretty small though, changing the key without changing passwords only matters if the encryption key is leaked without the hashes also being leaked. Aug 22, 2018 at 22:46

This "Onion" construct can be dangerous and should only be done if you have enough reviewers, it does however add multiple favorable properties compared to simple hashing:

The first unsalted MD5 can be done by clients or frontend servers. It normalizes charset and length and obfuscates passwords early on without being too CPU intensive.

The salt is read from the user database so it is not present on the client, this is was the first HMAC adds.

The crypto service (or better HSM) defends against brute force (as the secret key is not known). In fact this predates NIST recommendations to do exactly this. This peppering is not often done as it requires complicated system setup (HSM or process isolation) - something Facebook can afford.

Since the pepper step could be compromised by insiders, the data is then passed to scrypt, a function designed to make brute force testing of passwords more expensive.

The final step might not be needed, or maybe it is used to add some diversification (SHA2 instead of SHA1).

It looks a bit like snake oil overdo but the steps can be reasonable explained. If you compare it with the (much weaker) glibc-SHA2 Voodoo it is really clean.

BTW1: memorable Authenticator are generally a bad thing, such schemes can only reduce the risk of handling them.

BTW2: collision weakness of SHA1 does not apply to HMAC constructs and the short MD5 hash size does not hurt much here (as passwords almost always have even less entropy). It would be more risky for key derivation, but that’s not the task at hand.


The reason for the many layers is that over time requirements have changed.

Based on a talk I was present at, the following additional info may assist you in understanding the whole process:

Plain MD5 hashing was the original way of storing the password for the service. This was known to be weak, but short of getting everyone to log in and change their password or to have two (or more) different password formats in the database, the only way to improve security was to wrap the previous hash in another step. As it is layered it is called 'the onion'

You will notice that they did this by adding a properly salted hash as was recommended at the time.

The cryptoservice is used to detect patterns of attacks - either from one or more endpoints/servers/services or for a specific user. This allows proactive detection of attacks and mitigation.

The scrypt step provides a way to make hashing harder over time. As CPUs get faster, you can increase the hardness and make the total hashing time take around the same time.

The last HMAC step is mostly to just make the resulting hashes more uniform for database storage.

Is this a good idea for new deployments? No, but it was done only due to the scale and unique problem that Facebook has.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.