public static function needsRehash(
        string $stored,
        EncryptionKey $secretKey,
        string $level = KeyFactory::INTERACTIVE,
        string $additionalData = ''
    ): bool {
        $config = self::getConfig($stored);
        if (Binary::safeStrlen($stored) < ((int) $config->SHORTEST_CIPHERTEXT_LENGTH * 4 / 3)) {
            throw new InvalidMessage('Encrypted password hash is too short.');
        }

        // First let's decrypt the hash
        $hash_str = Crypto::decryptWithAd(
            $stored,
            $secretKey,
            $additionalData,
            $config->ENCODING
        )->getString();

        // Upon successful decryption, verify that we're using Argon2i
        if (!\hash_equals(
            Binary::safeSubstr($hash_str, 0, 10),
            \SODIUM_CRYPTO_PWHASH_STRPREFIX
        )) {
            return true;
        }

        // Parse the cost parameters:
        switch ($level) {
            case KeyFactory::INTERACTIVE:
                return !\hash_equals(
                    '$argon2id$v=19$m=65536,t=2,p=1$',
                    Binary::safeSubstr($hash_str, 0, 31)
                );
            case KeyFactory::MODERATE:
                return !\hash_equals(
                    '$argon2id$v=19$m=262144,t=3,p=1$',
                    Binary::safeSubstr($hash_str, 0, 32)
                );
            case KeyFactory::SENSITIVE:
                return !\hash_equals(
                    '$argon2id$v=19$m=1048576,t=4,p=1$',
                    Binary::safeSubstr($hash_str, 0, 33)
                );
            default:
                return true;
        }
    }
public static function needsRehash(
        string $stored,
        EncryptionKey $secretKey,
        string $level = KeyFactory::INTERACTIVE,
        string $additionalData = ''
    ): bool {
        $config = self::getConfig($stored);
        if (Binary::safeStrlen($stored) < ((int) $config->SHORTEST_CIPHERTEXT_LENGTH * 4 / 3)) {
            throw new InvalidMessage('Encrypted password hash is too short.');
        }

        // First let's decrypt the hash
        $hash_str = Crypto::decryptWithAd(
            $stored,
            $secretKey,
            $additionalData,
            $config->ENCODING
        )->getString();

        // Upon successful decryption, verify that we're using Argon2i
        if (!\hash_equals(
            Binary::safeSubstr($hash_str, 0, 10),
            \SODIUM_CRYPTO_PWHASH_STRPREFIX
        )) {
            return true;
        }

        // Parse the cost parameters:
        switch ($level) {
            case KeyFactory::INTERACTIVE:
                return !\hash_equals(
                    '$argon2id$v=19$m=65536,t=2,p=1$',
                    Binary::safeSubstr($hash_str, 0, 31)
                );
            case KeyFactory::MODERATE:
                return !\hash_equals(
                    '$argon2id$v=19$m=262144,t=3,p=1$',
                    Binary::safeSubstr($hash_str, 0, 32)
                );
            case KeyFactory::SENSITIVE:
                return !\hash_equals(
                    '$argon2id$v=19$m=1048576,t=4,p=1$',
                    Binary::safeSubstr($hash_str, 0, 33)
                );
            default:
                return true;
        }
    }
public static function needsRehash ( string $ stored , EncryptionKey $ secretKey , string $ level = KeyFactory :: INTERACTIVE , string $ additionalData = '' ) : bool { $ config = self :: getConfig ( $ stored ) ; if ( Binary :: safeStrlen ( $ stored ) < ( ( int ) $ config -> SHORTEST_CIPHERTEXT_LENGTH * 4 / 3 ) ) { throw new InvalidMessage ( 'Encrypted password hash is too short.' ) ; } // First let's decrypt the hash $ hash_str = Crypto :: decryptWithAd ( $ stored , $ secretKey , $ additionalData , $ config -> ENCODING ) -> getString ( ) ; // Upon successful decryption, verify that we're using Argon2i if ( ! \ hash_equals ( Binary :: safeSubstr ( $ hash_str , 0 , 10 ) , \ SODIUM_CRYPTO_PWHASH_STRPREFIX ) ) { return true ; } // Parse the cost parameters: switch ( $ level ) { case KeyFactory :: INTERACTIVE : return ! \ hash_equals ( '$argon2id$v=19$m=65536,t=2,p=1$' , Binary :: safeSubstr ( $ hash_str , 0 , 31 ) ) ; case KeyFactory :: MODERATE : return ! \ hash_equals ( '$argon2id$v=19$m=262144,t=3,p=1$' , Binary :: safeSubstr ( $ hash_str , 0 , 32 ) ) ; case KeyFactory :: SENSITIVE : return ! \ hash_equals ( '$argon2id$v=19$m=1048576,t=4,p=1$' , Binary :: safeSubstr ( $ hash_str , 0 , 33 ) ) ; default : return true ; } }
Is this password hash stale?

@param string $stored            Encrypted password hash
@param EncryptionKey $secretKey  The master key for all passwords
@param string $level             The security level for this password
@param string $additionalData    Additional authenticated data (if used to encrypt, mandatory)
@return bool                     Do we need to regenerate the hash or
ciphertext?

@throws Alerts\InvalidSignature
@throws CannotPerformOperation
@throws InvalidDigestLength
@throws InvalidMessage
@throws InvalidType
@throws \TypeError
Is this password hash stale?