Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Bcrypt SHA-384
<?php
class Foo
{
/**
* This is example code. Please feel free to use it for reference but don't just copy/paste it.
*
* @param string $username Unsafe user-supplied data: The username
* @param string $password Unsafe user-supplied data: The password
* @return int The primary key for that user account
* @throws InvalidUserCredentialsException
*/
public function authenticate(string $username, string $password): int
{
// Database lookup
$stmt = $this->db->prepare("SELECT userid, passwordhash, legacy_password FROM user_accounts WHERE username = ?");
$stmt->execute([$username]);
$stored = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$stored) {
// No such user, throw an exception
throw new InvalidUserCredentialsException();
}
if ($stored['legacy_password']) {
// This is the legacy password upgrade code
if ($this->verify(legacy_hashing_algorithm($password), $stored['passwordhash'])) {
$newhash = $this->hash($password);
$stmt = $this->db->prepare("UPDATE user_accounts SET passwordhash = ?, legacy_password = FALSE WHERE userid = ?");
$stmt->execute([$newhash, $stored['userid']]);
// Return the user ID (integer)
return $stored['userid'];
}
} elseif ($this->verify($password, $stored['passwordhash'])) {
// This is the general purpose upgrade code e.g. if a future version of PHP upgrades to Argon2
if (password_needs_rehash($stored['passwordhash'], PASSWORD_DEFAULT)) {
$newhash = $this->hash($password);
$stmt = $this->db->prepare("UPDATE user_accounts SET passwordhash = ? WHERE userid = ?");
$stmt->execute([$newhash, $stored['userid']]);
}
// Return the user ID (integer)
return $stored['userid'];
}
// When all else fails, throw an exception
throw new InvalidUserCredentialsException();
}
/**
* Bcrypt-SHA-384 Verification
*
* @param string $plaintext
* @param string $Hash
* @return bool
*/
protected function verify(string $plaintext, string $hash): bool
{
$prehash = \base64_encode(
\hash('sha384', $plaintext, true)
);
return \password_verify($prehash, $hash);
}
/**
* Creates a Bcrypt-SHA-384 hash
*
* @param string $plaintext
* @return string
*/
protected function hash(string $plaintext): string
{
return \password_hash(
\base64_encode(
\hash('sha384', $plaintext, true)
),
PASSWORD_DEFAULT,
['cost' => 12]
);
}
}
<?php
try {
$userid = $this->authenticate($username, $password);
// Update the session state
// Redirect to the post-authentication landing page
} catch (InvalidUserCredentialsException $e) {
// Log the failure
// Redirect to the login form
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment