Generate and verify secure Argon2 password hashes with customizable security parameters
Good balance of memory and time complexity
Argon2 is a key derivation function designed specifically for password hashing and credentials protection. As the winner of the 2015 Password Hashing Competition (PHC), it represents the current state-of-the-art in password security, offering strong protection against various attack vectors including brute force, side-channel, and time-memory trade-off attacks.
Argon2 comes in three variants, each optimized for different security priorities:
Variant | Primary Use Case | Strengths | Considerations |
---|---|---|---|
Argon2d | Maximum resistance to GPU cracking | Uses data-dependent memory access, making it resistant to GPU-based attacks | Potentially vulnerable to side-channel timing attacks |
Argon2i | Side-channel resistant applications | Uses data-independent memory access to prevent side-channel attacks | Less resistant to GPU cracking than Argon2d |
Argon2id Recommended | General-purpose password hashing | Hybrid approach combining benefits of both variants | Good balance for most applications |
Argon2id is generally recommended for most applications as it provides a good balance between resistance to side-channel attacks and GPU-based cracking attempts.
Argon2's security and performance are controlled by these key parameters:
The amount of memory required by the algorithm, measured in kilobytes. Higher values require more memory, making hardware-based attacks more expensive.
The number of iterations, controlling how computationally intensive the hashing will be. Higher values increase security but also increase processing time.
The number of parallel threads used during the hash computation. This should typically be set to the number of available CPU cores to maximize efficiency.
Higher parallelism can improve performance on multi-core systems but doesn't necessarily increase security proportionally. Setting it beyond your available CPU cores typically doesn't improve performance.
Increasing memory cost generally offers better security returns than just increasing time cost. When resources are limited, prioritize higher memory usage over higher iteration counts whenever possible.
An encoded Argon2 hash string follows this format:
$argon2id$v=19$m=65536,t=3,p=4$c2FsdHNhbHRzYWx0c2FsdA$RVZ7MR2V3LAZXCCWxs4sBuMYh8iARZP3HOYnQS2fPJg
Breaking down the components:
Scenario | Memory (m) | Time (t) | Parallelism (p) | Notes |
---|---|---|---|---|
Web Application | 64 MB | 3-4 | 2 | Good balance for most web authentication systems |
Sensitive Data | 256 MB | 4-6 | 4 | Financial applications, administrative accounts |
Critical Security | 1 GB+ | 8+ | 8 | Encryption keys, highly sensitive/valuable data |
Resource Constrained | 16-32 MB | 2 | 1 | Minimum recommended for shared hosting environments |
The goal is to choose parameters that make the hash function take about 500ms on your server. This is slow enough to deter attackers but fast enough not to impact user experience significantly.
Algorithm | Year | Memory Usage | Parallelization | Main Advantages | When to Use |
---|---|---|---|---|---|
MD5 | 1992 | Very Low | No | None (broken) | Never - obsolete and insecure |
SHA-256 | 2001 | Very Low | No | Cryptographic integrity | Not for passwords - too fast |
PBKDF2 | 2000 | Low | Limited | FIPS compliance, widely available | When compliance requires it or Argon2 unavailable |
Bcrypt | 1999 | Low (4KB) | No | Battle-tested, widely implemented | Good general choice, especially when Argon2 unavailable |
Scrypt | 2009 | High | Limited | Memory-hard, proven design | Good alternative to Argon2, widely available |
Argon2 | 2015 | Configurable | Yes | Modern design, flexible parameters | Current recommended standard when available |
If Argon2 isn't available in your environment, good alternatives in order of preference are:
Never use plain SHA-256, SHA-1, MD5, or other cryptographic hash functions without a specialized password hashing algorithm.
// Generate a password hash $hash = password_hash('user_password', PASSWORD_ARGON2ID, [ 'memory_cost' => 65536, // 64 MB 'time_cost' => 4, // 4 iterations 'threads' => 2 // 2 threads ]); // Verify a password if (password_verify('user_password', $hash)) { echo "Password is valid!"; } else { echo "Password is invalid!"; }
from argon2 import PasswordHasher # Create a password hasher ph = PasswordHasher( time_cost=4, # Iterations memory_cost=65536, # 64 MB parallelism=2, # 2 threads hash_len=32, # 32 bytes output type=2 # Argon2id (0=Argon2d, 1=Argon2i, 2=Argon2id) ) # Hash a password hash = ph.hash("user_password") # Verify a password try: ph.verify(hash, "user_password") print("Password is valid!") except: print("Password is invalid!")
const argon2 = require('argon2'); async function hashPassword() { try { // Generate a hash const hash = await argon2.hash("user_password", { type: argon2.argon2id, memoryCost: 65536, // 64 MB timeCost: 4, // 4 iterations parallelism: 2 // 2 threads }); console.log("Hash:", hash); // Verify a hash const isValid = await argon2.verify(hash, "user_password"); if (isValid) { console.log("Password is valid!"); } else { console.log("Password is invalid!"); } } catch (err) { console.error("Error:", err); } }
import com.kosprov.jargon2.api.Jargon2; // Create a password hasher Jargon2.Hasher hasher = Jargon2.jargon2Hasher() .type(Jargon2.Type.ARGON2id) .memoryCost(65536) // 64 MB .timeCost(4) // 4 iterations .parallelism(2) // 2 threads .encodedHash(); // Generate a hash String hash = hasher.password("user_password".getBytes()).hash(); // Verify a hash boolean isValid = Jargon2.jargon2Verifier() .hash(hash) .password("user_password".getBytes()) .verifyEncoded();
When selecting parameters for Argon2:
If you're currently using an older hashing algorithm, here's a gradual migration approach:
// Store new passwords with Argon2 $hash = password_hash($password, PASSWORD_ARGON2ID, [ 'memory_cost' => 65536, 'time_cost' => 4, 'threads' => 2 ]);
// Check password against existing hash (e.g., bcrypt) if (password_verify($password, $old_hash)) { // Login successful - rehash with Argon2 if (password_needs_rehash($old_hash, PASSWORD_ARGON2ID, [ 'memory_cost' => 65536, 'time_cost' => 4, 'threads' => 2 ])) { // Update stored hash to new Argon2 hash $new_hash = password_hash($password, PASSWORD_ARGON2ID, [ 'memory_cost' => 65536, 'time_cost' => 4, 'threads' => 2 ]); // Save $new_hash to database } // Continue with successful login }
Argon2 represents the current state-of-the-art in password hashing technology. Its memory-hard design and configurable parameters make it extremely resistant to hardware-based attacks while allowing developers to balance security and performance based on their specific requirements.
By following the guidelines presented here and selecting appropriate parameters for your application, you can significantly enhance the security of your users' credentials and protect against both current and future password cracking attempts.
Remember that password hashing is just one component of a comprehensive security strategy. Even the strongest hashing algorithm should be complemented with other security measures like rate limiting, multi-factor authentication, and proper security monitoring.