Engineering Article

BCrypt vs Argon2: Password Hashing in .NET – A Practical Deep Dive

I’ve worked with .NET for many years. One thing I never compromise on is password storage. Plain text or weak hashing is a disaster waiting to happen.

In this post, I break down BCrypt and Argon2 with technical details, internal differences, clean code examples, and when to choose which.

Why We Need Slow and Memory-Hard Hashing

Normal cryptographic hashes (SHA-256, etc.) are designed to be fast. Attackers with GPUs or ASICs can try billions of password guesses per second.

We need password-specific algorithms that are deliberately slow on purpose. They also generate a unique random salt for every password. This makes brute-force and rainbow table attacks extremely expensive.

BCrypt – The Battle-Tested Classic

BCrypt was created in 1999 based on the Blowfish cipher. It uses a modified expensive key schedule that repeats many times.

Technical details:

  • Fixed low memory usage (~4 KB per hash)
  • Controlled by a single “cost” parameter (work factor)
  • Cost = 13 means 2¹³ = 8,192 iterations
  • Purely CPU-bound

It is very simple and stable, but not memory-hard. Modern GPUs can run many BCrypt hashes in parallel quite cheaply.

Install: BCrypt.Net-Next

using BCrypt.Net;

public static class PasswordHasher
{
    private const int WorkFactor = 13;

    public static string Hash(string password)
        => BCrypt.Net.BCrypt.HashPassword(password, WorkFactor);

    public static bool Verify(string password, string hash)
        => BCrypt.Net.BCrypt.Verify(password, hash);
}

Argon2 – The Modern Standard

Argon2 won the Password Hashing Competition in 2015. It was built from scratch to be the best password hashing function.

Technical details:

  • Memory-hard algorithm (the key advantage)
  • Three variants: Argon2d, Argon2i, Argon2id
  • Argon2id is recommended for passwords (hybrid approach)
  • Configurable parameters: Memory size (m), Iterations (t), Parallelism (p)

The memory-hard property forces the attacker to use a lot of RAM for each attempt. This makes large-scale parallel attacks (on GPUs or ASICs) much more expensive.

Install: Isopoh.Cryptography.Argon2

using Isopoh.Cryptography.Argon2;

public static class PasswordHasher
{
    public static string Hash(string password)
        => Argon2.Hash(password);

    public static bool Verify(string password, string hash)
        => Argon2.Verify(hash, password);
}

This library uses secure defaults and handles salt + encoding automatically.

Key Internal Differences

  • Memory Usage:

    • BCrypt: Fixed ~4KB (not memory-hard)
    • Argon2: Configurable, typically 32MB–128MB+ (highly memory-hard)
  • Attack Resistance:

    • BCrypt: Good against CPU brute force, but weak against massive GPU parallelism
    • Argon2: Strong resistance to GPU, ASIC, and parallel attacks due to high memory requirement
  • Tuning:

    • BCrypt: Only one parameter (cost)
    • Argon2: Three tunable parameters (memory, time, threads)
  • Design Age:

    • BCrypt: 1999, based on Blowfish
    • Argon2: 2015, purpose-built for password hashing

When to Use Each

Use BCrypt when:

  • Maintaining legacy systems
  • Running on very low-memory servers
  • Need maximum simplicity

Use Argon2 when:

  • Building new applications
  • Handling sensitive user data
  • Want best protection against current and future hardware attacks

Important Things to Consider

  • Always benchmark on your production hardware. Aim for 400-800ms per hash
  • Argon2 consumes more RAM — test under concurrent load
  • When switching algorithms, rehash passwords on next successful login
  • Combine with login rate limiting and preferably 2FA