Menu

Implementing Argon2id Password Hashing in C#

Implementing Argon2id Password Hashing in C#

Argon2id is the gold standard for password hashing, combining the best features of Argon2i and Argon2d to provide excellent security against both side-channel and GPU-based attacks.

In this comprehensive guide, we'll explore how to implement Argon2id in your C# applications effectively.

What is Argon2id?

Argon2id is a key derivation function that won the Password Hashing Competition in 2015. It's specifically designed for password hashing and has become the recommended choice for new applications due to its security properties and performance characteristics.

Installing the Required Package

First, you'll need to install the official Konscious.Security.Cryptography.Argon2 NuGet package. You can do this via the Package Manager Console:

Install-Package Konscious.Security.Cryptography.Argon2 -Version 1.3.0

Or using the .NET CLI:

dotnet add package Konscious.Security.Cryptography.Argon2

Implementing Password Hashing with Argon2id

Here's a complete implementation of password hashing using Argon2id:

using System;
using System.Security.Cryptography;
using System.Text;
using Konscious.Security.Cryptography;

public class PasswordHasher
{
    private const int SaltSize = 16; // 128 bits
    private const int HashSize = 32; // 256 bits
    private const int DegreeOfParallelism = 8; // Number of threads to use
    private const int Iterations = 4; // Number of iterations
    private const int MemorySize = 1024 * 1024; // 1 GB

    public string HashPassword(string password)
    {
        // Generate a random salt
        byte[] salt = new byte[SaltSize];
        using (var rng = RandomNumberGenerator.Create())
        {
            rng.GetBytes(salt);
        }

        // Create hash
        byte[] hash = HashPassword(password, salt);

        // Combine salt and hash
        var combinedBytes = new byte[salt.Length + hash.Length];
        Array.Copy(salt, 0, combinedBytes, 0, salt.Length);
        Array.Copy(hash, 0, combinedBytes, salt.Length, hash.Length);

        // Convert to base64 for storage
        return Convert.ToBase64String(combinedBytes);
    }

    private byte[] HashPassword(string password, byte[] salt)
    {
        var argon2 = new Argon2id(Encoding.UTF8.GetBytes(password))
        {
            Salt = salt,
            DegreeOfParallelism = DegreeOfParallelism,
            Iterations = Iterations,
            MemorySize = MemorySize
        };

        return argon2.GetBytes(HashSize);
    }

    public bool VerifyPassword(string password, string hashedPassword)
    {
        // Decode the stored hash
        byte[] combinedBytes = Convert.FromBase64String(hashedPassword);

        // Extract salt and hash
        byte[] salt = new byte[SaltSize];
        byte[] hash = new byte[HashSize];
        Array.Copy(combinedBytes, 0, salt, 0, SaltSize);
        Array.Copy(combinedBytes, SaltSize, hash, 0, HashSize);

        // Compute hash for the input password
        byte[] newHash = HashPassword(password, salt);

        // Compare the hashes
        return CryptographicOperations.FixedTimeEquals(hash, newHash);
    }
}

Understanding the Parameters

The implementation above uses several important parameters that affect the security and performance of Argon2id:

  1. Salt Size: 16 bytes (128 bits) provides sufficient uniqueness for the salt.
  2. Hash Size: 32 bytes (256 bits) ensures a strong output hash.
  3. Degree of Parallelism: 8 threads balances performance and resource usage.
  4. Iterations: 4 passes increase the time cost.
  5. Memory Size: 1 GB makes the hashing resistant to GPU-based attacks.

Usage Example

Here's how to use the PasswordHasher class in your application:

public class Program
{
    public static void Main()
    {
        var hasher = new PasswordHasher();

        // Hash a password
        string password = "MySecurePassword123!";
        string hashedPassword = hasher.HashPassword(password);
        Console.WriteLine($"Hashed Password: {hashedPassword}");

        // Verify the password
        bool isValid = hasher.VerifyPassword(password, hashedPassword);
        Console.WriteLine($"Password is valid: {isValid}");
    }
}

Security Best Practices

When implementing password hashing with Argon2id, keep these security considerations in mind:

  1. Never store plaintext passwords: Always hash passwords immediately upon receipt.
  2. Use secure parameter values: Adjust the memory, iterations, and parallelism based on your server's capabilities.
  3. Implement rate limiting: Protect against brute-force attacks by limiting login attempts.
  4. Use HTTPS: Always transmit passwords over encrypted connections.
  5. Consider password policies: Enforce minimum length and complexity requirements.

Performance Considerations

The parameters used in this implementation are relatively conservative. Depending on your specific needs, you might want to adjust them:

  • Increase MemorySize for stronger security on high-end servers
  • Decrease MemorySize for better performance on resource-constrained systems
  • Adjust DegreeOfParallelism based on your CPU cores
  • Modify Iterations to balance security and performance

Conclusion

Implementing Argon2id in C# provides strong password hashing security for your applications. The implementation above offers a good balance between security and performance, but remember to adjust the parameters based on your specific requirements and hardware capabilities.

Remember to regularly update your dependencies and stay informed about security best practices, as recommendations may change over time.

References

Walter Guevara is a Computer Scientist, software engineer, startup founder and previous mentor for a coding bootcamp. He has been creating software for the past 20 years.
AD: "Heavy scripts slowing down your site? I use Fathom Analytics because it’s lightweight, fast, and doesn’t invade my users privacy." - Get $10 OFF your first invoice.
#c#

Community Comments

No comments posted yet

Code Your Own Classic Snake Game – The Right Way

Master the fundamentals of game development and JavaScript with a step-by-step guide that skips the fluff and gets straight to the real code.

Ad Unit

Current Poll

Help us and the community figure out what the latest trends in coding are.

Total Votes:
Q:
Submit

Add a comment