53

What are the considerations when picking the best password hashing algorithm in .NET Core?

I read that not all hashing algorithms are compliant / unverified, so I am a hesitant on just getting various implementations from NuGet. Also, it is not recommended to create your own hashing algorithm as verifying it needs some processes / money involved.

Currently, I am using .NET Core Identity V3 password hashing because at least it is something official that Microsoft provides.

I read that the following algorithms are the best:

  1. Argon2
  2. bcrypt
  3. scrypt
  4. Catena
  5. PBKDF2 (what .NET Core Identity V3 uses)

I would like Argon2 or bcrypt ideally. However, I don't want to just use the first thing that Google turns up. Also, how do I know which ones are verified / recommended?

4
  • scrypt is definitely better than bcrypt. bcrypt was made to be hard for ASICS (the main danger at the time), scrypt added memory hard. Sep 2, 2019 at 9:13
  • @BrunoRohée bcrypt is actually pretty good against GPUs as well due to use of contended memory.
    – forest
    Sep 3, 2019 at 1:46
  • 1
    @BrunoRohée To echo what forest said but with a little more emphasis, scrypt is not definitely better than bcrypt for some purposes.
    – Xander
    Sep 3, 2019 at 2:16
  • The best at what? If this is for quick value lookups, then these are all terrible choices. A prefilter for data deduplication? All rubbish! Part of a bloom filter? Worst options ever. These listed aren't even hash functions anyways; they're key stretching algorithms with tunable difficulties that make them great for preventing brute-force confirmation of a plaintext... but absolute trash at the things that hash functions should be used for. (Of course, hash functions are trash at protecting passwords and other plaintexts, so...)
    – Ghedipunk
    Sep 3, 2019 at 22:26

3 Answers 3

42

Argon2 is the best of those to use. It has been well-vetted and is the subject of intense research. It was chosen as the winner in the Password Hashing Competition (PHC) to replace scrypt, which has some nasty time-memory tradeoff (TMTO) attacks, and which is not nearly as flexible in configuration.


Argon2 won the PHC and is based on a thorough analysis of tradeoff attacks. It requires a configurable amount of memory to run, and an attacker will either need to use that much memory per brute force thread, or they will need to perform drastically more computations. Each memory pass reduces the flexibility an attacker has to trade memory requirements for time requirements. There are two primary Argon2 modes, called Argon2i and Argon2d. The former is designed to resist side-channel attacks, whereas the latter is designed to maximize security against offline attacks. A hybrid, Argon2id, which uses Argon2i for the first memory pass and Argon2d for subsequent passes, also exists.

bcrypt is an older KDF designed from the key schedule of Blowfish, which is slow. It requires 4 KiB of fast memory to compute, which makes it inefficient on GPU-based crackers due to their use of contended memory. This is because GPUs have many cores, but each core has to share access to the main VRAM. Because bcrypt reads and modifies a 4 KiB state as it runs, multiple parallel GPU cores will fight over who gets access to the main memory bus, and the result is that most cores are idling, waiting until they have access to the memory they need to perform bcrypt evaluations.

scrypt is a memory-hard KDF, but it is subject to more severe TMTO attacks than Argon2. That is, if an attacker doesn't have enough memory, they can run scrypt over the same input with less memory than required by performing more operations. Additionally, scrypt's internal memory and time requirements are not independent, so it is impossible to increase memory usage without increasing processing time, and vice versa. This may become an issue for servers that might want to spend only a few tens of milliseconds on each computation, but which want to use several megabytes of memory.

Catena was one of the PHC candidates, but it did not win the competition. I haven't read the paper so I can't really say much about it, but because it did not win, it won't have nearly as much research going into it, so if there are any issues, they may not be discovered. It is not, however, a bad choice, as it was still the subject of significant research and has a solid theoretical foundation. I still wouldn't use it.

PBKDF2 is one of the oldest KDFs, and is likely the most common. It is not memory hard, which means an attacker can perform massively parallel attacks against it without running into memory issues. PBKDF2 works by taking any keyed hash, typically HMAC, and running it multiple times such that each hash evaluation depends on all the previous hash evaluations. Unfortunately, typical hashes used in HMAC require next to no memory to compute, so an attacker can massively parallelize brute force searches on GPUs and ASICs without running into the issues that a memory-hard KDF would cause.

10
  • 2
    Thanks forest, Argon2 seems good. Although is it safe to assume that ports of it (ex. Libsodium or any other implementation) really follow its algorithm? Is there like a list of verified implementations?
    – Water
    Sep 2, 2019 at 8:49
  • 3
    @Water This can be done by yourself quite easily. All you had to do was create a hash using the implementation of your choice, then verify it using the reference implementation and vice versa.
    – user163495
    Sep 2, 2019 at 9:00
  • 1
    So does .NET core support all Argon2 modes then? Sep 3, 2019 at 1:41
  • 1
    @MechMK1 that's not sufficient - you'd have to check every possible input (which is infeasible) to confirm whether a black box is a correct implementation of Argon2.
    – OrangeDog
    Sep 3, 2019 at 17:39
  • 1
    @OrangeDog: having all output of an implementation match the reference implementation is necessary, but it isn't sufficient to consider an alternate crypto implementation secure. Even if the output matches, an implementation may still be subject to side channel attacks (e.g. timing, electromagnetic emission). Many side channel attacks are somewhat a bit in the realm of science fiction, but some have the potential to become practical in the future or under certain limited circumstances.
    – Lie Ryan
    Sep 4, 2019 at 4:26
18

While the other responses debate the effectiveness of each algorithm from the list, I will attempt answer from the .NET Core perspective. Unless things have changed recently, the only algorithm from your list that is natively supported (ie authored by Microsoft) in .NET Core is PBKDF2. For some companies, this means that this is your only choice. If you have the luxury of being able to use any third party NuGet package then you will find numerous implementations of many of the other algorithms in you list, but you will have to decide if you trust them. Personally, from the low numbers of downloads, I would be uncomfortable using anything other than perhaps BCrypt-Official but even then, I might want to research it further. It is important to consider that anyone can author a NuGet package (and call it 'official' if they like) and that most packages are unlikely to go through any review process so it is up to you to do your homework.

14

Even though Argon2 is my personal favorite among them, all of them are solid choices and you will likely not get weird looks for choosing one over the other. What matters the most is that you properly benchmark your system, so that you choose sane parameters.

With Argon2, you additionally have to select a mode-of-operation. There is Argon2i, Argon2d and Argon2id. Unless you know you have a good reason to pick one of the first two, you should pick Argon2id.

12
  • 1
    Well PBKDF2 I'd be a little iffy with, but at least it's not bad (just not memory hard).
    – forest
    Sep 2, 2019 at 8:08
  • 3
    @forest Yes, it's not, but PBKDF2 with like 1000000 rounds is still probably more secure than your regular run-of-the-mill SHA1(password + salt) implementation
    – user163495
    Sep 2, 2019 at 8:11
  • 1
    do Argon2i, Argon2d, and Argon2id available in .Net Core?
    – kelalaka
    Sep 2, 2019 at 9:53
  • 4
    Who do you consider "official"? Implemented by Microsoft? Implemented by the authors of Argon2?
    – user163495
    Sep 3, 2019 at 8:46
  • 4
    Do not use a .NET implementation of Argon2. Use a binding of the official library. I know that's probably what everyone meant, but it would be a big problem to use a sketchy re-implementation of the algorithm. The number one issue would be potential bugs. Secondary to that, you want to use an efficient implementation of any so called "slow hash" function. It does no good to be wasteful on the defender's side. It's not enough to just run slowly on your own machine. Sep 3, 2019 at 15:29

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .