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:
- Salt Size: 16 bytes (128 bits) provides sufficient uniqueness for the salt.
- Hash Size: 32 bytes (256 bits) ensures a strong output hash.
- Degree of Parallelism: 8 threads balances performance and resource usage.
- Iterations: 4 passes increase the time cost.
- 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:
- Never store plaintext passwords: Always hash passwords immediately upon receipt.
- Use secure parameter values: Adjust the memory, iterations, and parallelism based on your server's capabilities.
- Implement rate limiting: Protect against brute-force attacks by limiting login attempts.
- Use HTTPS: Always transmit passwords over encrypted connections.
- Consider password policies: Enforce minimum length and complexity requirements.
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.
Last updated on:
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.