<commit_before><?php
/**
 * @author <NAME> <<EMAIL>>
 * @copyright 2009-2014 Vanilla Forums Inc.
 * @license MIT
 */

namespace Garden\Password;


/**
 * Implements the password hashing algorithm of Xenforo.
 *
 */
class XenforoPassword implements IPassword {

    /**
     * @var string The name of the hashing function to use.
     */
    protected $hashFunction;

    /**
     * Initialize an instance of this class.
     *
     * @param string $hashFunction The name of the hash function to use.
     * This is an function name that can be passed to {@link hash()}.
     * @see hash()
     */
    public function __construct($hashFunction = '') {
        if (!$hashFunction) {
            $hashFunction = 'sha256';
        }
        $this->hashFunction = $hashFunction;
    }

    /**
     * {@inheritdoc}
     */
    public function hash($password) {
        $salt = base64_encode(openssl_random_pseudo_bytes(12));
        $result = [
            'hashFunc' => $this->hashFunction,
            'hash' => $this->hashRaw($password, $salt, $this->hashFunction),
            'salt' => $salt
        ];

        return serialize($result);
    }

    /**
     * Hashes a password with a given salt.
     *
     * @param string $password The password to hash.
     * @param string $salt The password salt.
     * @param string $function The hashing function to use.
     * @return string Returns the password hash.
     */
    protected function hashRaw($password, $salt, $function = null) {
        if ($function === null) {
            $function = $this->hashFunction;
        }

        $calc_hash = hash($function, hash($function, $password).$salt);

        return $calc_hash;
    }

    /**
     * {@inheritdoc}
     */
    public function needsRehash($hash) {
        list($stored_hash, $stored_salt) = $this->splitHash($hash);

        // Unsalted hashes should be rehashed.
        if ($stored_hash === false || $stored_salt === false) {
            return true;
        }

        return false;
    }

    /**
     * {@inheritdoc}
     */
    public function verify($password, $hash) {
        list($stored_hash, $function, $stored_salt) = $this->splitHash($hash);

        $calc_hash = $this->hashRaw($password, $stored_salt, $function);
        $result = $calc_hash === $stored_hash;

        return $result;
    }

    /**
     * Split the hash into its calculated hash and salt.
     *
     * @param string $hash The hash to split.
     * @return array An array in the form [$hash, $hashFunc, $salt].
     */
    protected function splitHash($hash) {
        $parts = @unserialize($hash);

        if (!is_array($parts)) {
            $Result = ['', '', ''];
        } else {
            $parts = array_merge(['hash' => '', 'hashFunc' => '', 'salt' => ''], $parts);

            if (!$parts['hashFunc']) {
                switch (strlen($parts['hash'])) {
                    case 32:
                        $parts['hashFunc'] = 'md5';
                        break;
                    case 40:
                        $parts['hashFunc'] = 'sha1';
                        break;
                }

            }

            $result = [$parts['hash'], $parts['hashFunc'], $parts['salt']];
            return $result;
        }
    }
}<commit_msg>Fix missing result in XenforoPassword->splitHash().<commit_after><?php
/**
 * @author <NAME> <<EMAIL>>
 * @copyright 2009-2014 Vanilla Forums Inc.
 * @license MIT
 */

namespace Garden\Password;


/**
 * Implements the password hashing algorithm of Xenforo.
 *
 */
class XenforoPassword implements IPassword {

    /**
     * @var string The name of the hashing function to use.
     */
    protected $hashFunction;

    /**
     * Initialize an instance of this class.
     *
     * @param string $hashFunction The name of the hash function to use.
     * This is an function name that can be passed to {@link hash()}.
     * @see hash()
     */
    public function __construct($hashFunction = '') {
        if (!$hashFunction) {
            $hashFunction = 'sha256';
        }
        $this->hashFunction = $hashFunction;
    }

    /**
     * {@inheritdoc}
     */
    public function hash($password) {
        $salt = base64_encode(openssl_random_pseudo_bytes(12));
        $result = [
            'hashFunc' => $this->hashFunction,
            'hash' => $this->hashRaw($password, $salt, $this->hashFunction),
            'salt' => $salt
        ];

        return serialize($result);
    }

    /**
     * Hashes a password with a given salt.
     *
     * @param string $password The password to hash.
     * @param string $salt The password salt.
     * @param string $function The hashing function to use.
     * @return string Returns the password hash.
     */
    protected function hashRaw($password, $salt, $function = null) {
        if ($function === null) {
            $function = $this->hashFunction;
        }

        $calc_hash = hash($function, hash($function, $password).$salt);

        return $calc_hash;
    }

    /**
     * {@inheritdoc}
     */
    public function needsRehash($hash) {
        list($stored_hash, $stored_salt) = $this->splitHash($hash);

        // Unsalted hashes should be rehashed.
        if ($stored_hash === false || $stored_salt === false) {
            return true;
        }

        return false;
    }

    /**
     * {@inheritdoc}
     */
    public function verify($password, $hash) {
        list($stored_hash, $function, $stored_salt) = $this->splitHash($hash);

        $calc_hash = $this->hashRaw($password, $stored_salt, $function);
        $result = $calc_hash === $stored_hash;

        return $result;
    }

    /**
     * Split the hash into its calculated hash and salt.
     *
     * @param string $hash The hash to split.
     * @return array An array in the form [$hash, $hashFunc, $salt].
     */
    protected function splitHash($hash) {
        $parts = @unserialize($hash);

        if (!is_array($parts)) {
            $result = ['', '', ''];
        } else {
            $parts = array_merge(['hash' => '', 'hashFunc' => '', 'salt' => ''], $parts);

            if (!$parts['hashFunc']) {
                switch (strlen($parts['hash'])) {
                    case 32:
                        $parts['hashFunc'] = 'md5';
                        break;
                    case 40:
                        $parts['hashFunc'] = 'sha1';
                        break;
                }
            }

            $result = [$parts['hash'], $parts['hashFunc'], $parts['salt']];
        }
        return $result;
    }
}
{'fraction_non_alphanumeric': 0.14420875934686403, 'fraction_numerical': 0.006409278193193957, 'mean_word_length': 1.8745614035087719, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 38, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4018804', 'n_tokens_mistral': 1954, 'n_tokens_neox': 1834, 'n_words': 490}