Click the Castor logo or press Ctrl Alt T to change theme.
# Password hashing Passwords are low-entropy secrets chosen by humans. They need a slow, memory-hard password hash, not encryption and not a fast digest. Castor Crypto wraps libsodium's Argon2 password APIs through `Password`. ## Registration When a user creates an account, hash the submitted password and store only the resulting hash string. ```php <?php use Castor\Crypto\Password; use Castor\Crypto\Secret; $password = Secret::raw($_POST['password']); $hash = Password::hash($password, Password\Config::default()); $db->insert('users', [ 'email' => $_POST['email'], 'password_hash' => $hash->toString(), ]); ``` The stored value includes the algorithm, salt, and cost parameters. You do not need a separate salt column. ## Login Restore the stored hash and verify the submitted password. ```php $hash = Password::raw($user['password_hash']); $submitted = Secret::raw($_POST['password']); if (!$hash->verify($submitted)) { // Use a generic "invalid credentials" response. } ``` Avoid telling the user whether the email or password was wrong. That difference helps account enumeration. ## Rehash as hardware changes Password costs should increase over time. When a user logs in successfully, check whether the stored hash was made with your current policy. ```php $config = Password\Config::default(); if ($hash->verify($submitted) && $hash->needsRehash($config)) { $newHash = Password::hash($submitted, $config); $db->update('users', $user['id'], ['password_hash' => $newHash->toString()]); } ``` This upgrades active accounts gradually without forcing every user to reset their password. ## Choosing a cost `Config::default()` is the right starting point for normal applications. `Config::fast()` is useful for tests or very latency-sensitive flows after measuring the risk. `Config::strong()` spends more resources and may be appropriate for administrative accounts or low-volume systems. The tradeoff is direct: higher cost slows attackers, but it also consumes your CPU and memory. Measure under production-like concurrency before raising costs globally. ## Password-derived keys Sometimes you need to derive a fixed-length key from a password, for example for a user-controlled encrypted export. Use a random salt and store it next to the encrypted data. ```php <?php use Castor\Crypto\Password; use Castor\Crypto\Password\Salt; use Castor\Crypto\Secret; $salt = Salt::generate(); $key = Password::derive( Secret::raw($password), $salt, length: 32, config: Password\Config::strong(), ); ``` Do not use password derivation as a replacement for login password hashing. Login verification should use `Password::hash()` and `verify()`. ## Attack vectors A database leak gives attackers the password hashes. Argon2 makes guessing expensive, but weak passwords can still be found. Rate limiting protects your online login form; password hashing protects the offline breach scenario. You need both. Treat submitted passwords as secrets. Do not log request bodies on authentication routes, and be careful with exception reporting tools that capture form fields.
Castor ecosystem