Rustelo/info/argon2_migration.md

219 lines
6.1 KiB
Markdown
Raw Normal View History

# 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$<salt>$<hash>`
- `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<String, bcrypt::BcryptError> {
hash(password, self.cost)
}
pub fn verify_password(&self, password: &str, hash: &str) -> Result<bool, bcrypt::BcryptError> {
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<String, argon2::password_hash::Error> {
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<bool, argon2::password_hash::Error> {
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.