# 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.