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;
        }
    }