3
\$\begingroup\$

I've constructed a simple class whose entire purpose is to hash passwords securely and simply.

The catch is the PHP version is probably going to be 5.2.x. This means:

  • No CRYPT_BLOWFISH
  • Obviously no password_hash().

The question is, is the following secure? Can it be improved?

/**
 * Class Hasher
 *
 * @package Dependencies\Hasher
 *
 * Defines hashing mechanism for password saving.
 */
class Hasher {

    /**
     * @param string $string String for hashing
     * @param string $salt   Unique salt. The salt is best kept as a very long, very random string.
     * @param int    $cost   Cost parameter. 2^$cost iterations over the hashing algorithm.
     *
     * @return string
     */
    public function algo($string, $salt, $cost) {
        $iterations = pow(2, $cost);
        $result     = "";

        for ($i = 0; $i < $iterations; $i++) {
            $result = sha1($result . $salt . $string);
        }

        return $result;
    }

    /**
     * Pass a password through the hashing algorithm. And return the result.
     *
     * @param string $password
     * @param string $salt
     * @param int    $cost
     *
     * @return string
     */
    public final function hash($password, $salt, $cost = 10) {
        return $this->algo($password, $salt, $cost);
    }

    /**
     * Match password through the hashing algorithm against an existing hash to make sure there's a match.
     *
     * @param string $hash
     * @param string $password
     * @param string $salt
     * @param int    $cost
     *
     * @return bool
     */
    public final function verify($hash, $password, $salt, $cost = 10) {
        return $this->algo($password, $salt, $cost) == $hash;
    }

}
\$\endgroup\$

2 Answers 2

6
\$\begingroup\$

There are several improvements to this that involve various algorithms that are more cryptographically secure than sha1 (such as sha256 or higher, blowfish, whirlpool, etc.), using strict comparison (to avoid that gotcha with very long hashes loosely comparing when not equal), and including a CSPRNG salting function in the class, that takes over when a user does not supply a salt.

However, CRYPT_BLOWFISH is still very usable in PHP < 5.3. In fact, It's usable in PHP 3.0.18 and over, with the use of PHPass, by the same security company who make John the Ripper (which you should be using to test your class. Try and get the UNIQPASS wordlist. It's really effective!). An alternative to JtR is hashcat. There are several defcon talks about correct usage of password crackers to test strength (by the feds), among other uses (by the non-feds).

If you really must roll your own, then consider implementing blowfish manually.

\$\endgroup\$
4
\$\begingroup\$

Just use PHPass when your PHP version is too low for the native password API instead of trying to roll your own implementation.

http://www.openwall.com/phpass/

Although you should really update your PHP version, but you already know that.

\$\endgroup\$
1
  • 4
    \$\begingroup\$ You know me. If I had a choice, I'd update. \$\endgroup\$ Commented Apr 2, 2013 at 18:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.