PHP Classes

File: src/Password.php

Recommend this page to a friend!
  Packages of Scott Arciszewski   Halite   src/Password.php   Download  
File: src/Password.php
Role: Class source
Content type: text/plain
Description: Class source
Class: Halite
Perform cryptography operations with libsodium
Author: By
Last change: For version 2, let's use strict types!
Switch passwords and key derivation to crypto_pwhash() (Argon2i)
Date: 10 years ago
Size: 2,582 bytes
 

Contents

Class file image Download
<?php
declare(strict_types=1);
namespace ParagonIE\Halite;

use \ParagonIE\Halite\{
    Contract\PasswordInterface,
    Contract\KeyInterface,
    Symmetric\Crypto,
    Symmetric\EncryptionKey,
    Util as CryptoUtil
};

/**
 * Secure password storage and secure password verification
 */
abstract class Password implements PasswordInterface
{
    /**
     * Hash then encrypt a password
     * 
     * @param string $password         - The user's password
     * @param EncryptionKey $secret_key - The master key for all passwords
     * @return string
     */
    public static function hash(string $password, KeyInterface $secret_key): string
    {
        if (!($secret_key instanceof EncryptionKey)) {
            throw new \ParagonIE\Halite\Alerts\InvalidKey(
                'Argument 2: Expected an instance of EncryptionKey'
            );
        }
        // First, let's calculate the hash
        $hashed = \Sodium\crypto_pwhash_str(
            $password,
            \Sodium\CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
            \Sodium\CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
        );
        
        // Now let's encrypt the result
        return Crypto::encrypt($hashed, $secret_key);
    }

    /**
     * Decrypt then verify a password
     * 
     * @param string $password          - The user-provided password
     * @param string $stored            - The encrypted password hash
     * @param EncryptionKey $secret_key  - The master key for all passwords
     * @return boolean
     */
    public static function verify(
        string $password,
        string $stored,
        KeyInterface $secret_key
    ): bool {
        if (!($secret_key instanceof EncryptionKey)) {
            throw new \ParagonIE\Halite\Alerts\InvalidKey(
                'Argument 3: Expected an instance of EncryptionKey'
            );
        }
        // First let's decrypt the hash
        $hash_str = Crypto::decrypt($stored, $secret_key);
        // Upon successful decryption, verify the password is correct
        $isArgon2 = \hash_equals(
            CryptoUtil::safeSubstr($hash_str, 0, 9),
            \Sodium\CRYPTO_PWHASH_STRPREFIX
        );
        $isScrypt = \hash_equals(
            CryptoUtil::safeSubstr($hash_str, 0, 3),
            \Sodium\CRYPTO_PWHASH_SCRYPTSALSA208SHA256_STRPREFIX
        );
        if ($isArgon2) {
            return \Sodium\crypto_pwhash_str_verify($hash_str, $password);
        } elseif ($isScrypt) {
            return \Sodium\crypto_pwhash_scryptsalsa208sha256_str_verify($hash_str, $password);
        }
        return false;
    }
}