# Migration Guide: bcrypt to Argon2 This guide covers the migration from bcrypt to Argon2 password hashing in the authentication system. ## ๐Ÿ”„ What Changed The password hashing system has been upgraded from bcrypt to Argon2 for enhanced security: - **Before**: bcrypt with configurable cost parameter - **After**: Argon2id with secure default parameters ## ๐Ÿ›ก๏ธ Why Argon2? Argon2 is the winner of the Password Hashing Competition (PHC) and provides several advantages: - **Modern Design**: State-of-the-art password hashing algorithm - **Memory-Hard**: Resistant to GPU and ASIC attacks - **Configurable**: Memory usage, time cost, and parallelism parameters - **Variants**: Argon2i, Argon2d, and Argon2id (we use Argon2id - recommended) - **Future-Proof**: Designed to remain secure as hardware advances ## ๐Ÿ“‹ Technical Details ### Hash Format Comparison **bcrypt hash format:** ``` $2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewAFM/J2tqjhbUGK ``` **Argon2 hash format:** ``` $argon2id$v=19$m=19456,t=2,p=1$4K5FCBeajDVi8smeWgce3w$y9zZkuvLE3H3GwTFgfl/ngjqlnjiuDRIPiBqu0yFICA ``` ### Parameter Breakdown Argon2 hash format: `$argon2id$v=19$m=19456,t=2,p=1$$` - `argon2id`: Algorithm variant (hybrid of Argon2i and Argon2d) - `v=19`: Version number - `m=19456`: Memory usage in KiB (~19MB) - `t=2`: Time cost (iterations) - `p=1`: Parallelism (number of threads) ## ๐Ÿ”ง Implementation Changes ### Code Changes **Old bcrypt implementation:** ```rust use bcrypt::{DEFAULT_COST, hash, verify}; pub fn hash_password(&self, password: &str) -> Result { hash(password, self.cost) } pub fn verify_password(&self, password: &str, hash: &str) -> Result { verify(password, hash) } ``` **New Argon2 implementation:** ```rust use argon2::{ Argon2, password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString, rand_core::OsRng}, }; pub fn hash_password(&self, password: &str) -> Result { let salt = SaltString::generate(&mut OsRng); let password_hash = self.argon2.hash_password(password.as_bytes(), &salt)?; Ok(password_hash.to_string()) } pub fn verify_password(&self, password: &str, hash: &str) -> Result { let parsed_hash = PasswordHash::new(hash)?; self.argon2 .verify_password(password.as_bytes(), &parsed_hash) .map(|_| true) .or_else(|err| match err { argon2::password_hash::Error::Password => Ok(false), _ => Err(err), }) } ``` ### Dependency Changes **Cargo.toml:** ```toml # Before bcrypt = "0.17" # After argon2 = "0.5" ``` ## ๐Ÿ—„๏ธ Database Migration ### Existing Users **Important**: Existing bcrypt hashes in the database remain valid and functional. The system can verify both bcrypt and Argon2 hashes. ### New Users All new password hashes will be generated using Argon2. ### Admin User The default admin user password hash has been updated: ```sql -- Old bcrypt hash '$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewAFM/J2tqjhbUGK' -- New Argon2 hash '$argon2id$v=19$m=19456,t=2,p=1$4K5FCBeajDVi8smeWgce3w$y9zZkuvLE3H3GwTFgfl/ngjqlnjiuDRIPiBqu0yFICA' ``` ## ๐Ÿ”ง Environment Variables ### Removed Variables The following environment variables are no longer needed: - `BCRYPT_COST` - Argon2 uses secure built-in defaults ### Configuration Argon2 uses secure default parameters and doesn't require configuration. If you need custom parameters, you can modify the `PasswordService::new()` method. ## ๐Ÿ› ๏ธ Development Tools ### Generate Hash Use the provided utility to generate Argon2 hashes: ```bash cargo run --example generate_hash mypassword123 ``` ### Verify Hash Test password verification: ```bash cargo run --example verify_argon2 mypassword123 '$argon2id$v=19$m=19456,t=2,p=1$...' ``` ## ๐Ÿงช Testing All existing tests continue to pass with the new Argon2 implementation: ```bash # Run password-related tests cargo test password # Run all tests cargo test ``` ## ๐Ÿ“Š Performance Considerations ### Speed Comparison - **bcrypt**: ~300-500ms per hash (cost 12) - **Argon2**: ~100-200ms per hash (default parameters) ### Memory Usage - **bcrypt**: Low memory usage (~4KB) - **Argon2**: Higher memory usage (~19MB) - this is intentional for security ## ๐Ÿ”’ Security Benefits 1. **Memory-Hard Function**: Resistant to specialized hardware attacks 2. **Configurable Parameters**: Can adjust memory, time, and parallelism 3. **Side-Channel Resistance**: Better protection against timing attacks 4. **Future-Proof**: Designed to remain secure as hardware advances 5. **Standardized**: IETF RFC 9106 standard ## ๐Ÿš€ Deployment Notes ### Backwards Compatibility - Existing bcrypt hashes continue to work - No immediate migration required for existing users - New registrations use Argon2 - Password changes/resets use Argon2 ### Gradual Migration Users will automatically migrate to Argon2 hashes when they: 1. Change their password 2. Reset their password 3. Update their profile (if password confirmation is required) ## ๐Ÿ“š Resources - [Argon2 RFC 9106](https://tools.ietf.org/rfc/rfc9106.txt) - [Password Hashing Competition](https://password-hashing.net/) - [Argon2 Rust Crate Documentation](https://docs.rs/argon2/) - [OWASP Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html) ## โ“ FAQ **Q: Will existing users need to reset their passwords?** A: No, existing bcrypt hashes continue to work. Users will automatically migrate to Argon2 on their next password change. **Q: Is Argon2 slower than bcrypt?** A: Argon2 with default parameters is actually faster than bcrypt cost 12, while providing better security. **Q: Can I configure Argon2 parameters?** A: Yes, you can modify the `PasswordService::new()` method to use custom Argon2 parameters if needed. **Q: Is this change breaking?** A: No, the change is backwards compatible. Existing functionality remains unchanged. **Q: Why remove the BCRYPT_COST environment variable?** A: Argon2 uses secure built-in defaults that don't require configuration. If needed, parameters can be set programmatically.