Password Hashing in 2013

2019-02-14 22:20发布

问题:

What is the "best" solution these today?

This seems a good option: https://defuse.ca/php-pbkdf2.htm

But then how about upgrading to PHP5.5 and using this? http://php.net/manual/en/function.hash-pbkdf2.php

Curious as to why the PHP site states:

Caution The PBKDF2 method can be used for hashing passwords for storage (it is NIST approved for that use). However, it should be noted that CRYPT_BLOWFISH is better suited for password storage and should be used instead via crypt().

For PHP versions less that 5.5 would it be fair to use the defuse.ca solution, and then just switch it out after upgrading to PHP5.5?

/*
 * PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt
 * $algorithm - The hash algorithm to use. Recommended: SHA256
 * $password - The password.
 * $salt - A salt that is unique to the password.
 * $count - Iteration count. Higher is better, but slower. Recommended: At least 1000.
 * $key_length - The length of the derived key in bytes.
 * $raw_output - If true, the key is returned in raw binary format. Hex encoded otherwise.
 * Returns: A $key_length-byte key derived from the password and salt.
 *
 * Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
 *
 * This implementation of PBKDF2 was originally created by https://defuse.ca
 * With improvements by http://www.variations-of-shadow.com
 */
function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
    $algorithm = strtolower($algorithm);
    if(!in_array($algorithm, hash_algos(), true))
        die('PBKDF2 ERROR: Invalid hash algorithm.');
    if($count <= 0 || $key_length <= 0)
        die('PBKDF2 ERROR: Invalid parameters.');

    $hash_length = strlen(hash($algorithm, "", true));
    $block_count = ceil($key_length / $hash_length);

    $output = "";
    for($i = 1; $i <= $block_count; $i++) {
        // $i encoded as 4 bytes, big endian.
        $last = $salt . pack("N", $i);
        // first iteration
        $last = $xorsum = hash_hmac($algorithm, $last, $password, true);
        // perform the other $count - 1 iterations
        for ($j = 1; $j < $count; $j++) {
            $xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
        }
        $output .= $xorsum;
    }

    if($raw_output)
        return substr($output, 0, $key_length);
    else
        return bin2hex(substr($output, 0, $key_length));
}

This is the current solution from defuse.ca, would it be fair to rename this function to hash_pbkdf2() and after upgrading to PHP5.5 transition would be nice and smooth?

回答1:

The accepted best practice in PHP passwords, as of PHP 5.5, is password_hash. It presents a single, unified, built-in, future-compatible way to generate a secure password hash.

If you are using a security-updated version of 5.3.x or higher, you can use the password_compat library instead.

Under the covers, the current version makes calls to crypt with some predefined security options. Future versions may change the default options.

Please be sure to carefully read the section on the crypt page that talks about CRYPT_BLOWFISH versioning, as well as review the versioning notes on the password_compat page.

As noted clearly in the warning message, PBKDF2 is accepted by the NIST as an adequate way to store passwords. You can use implementations of it without significant concern, but you should only do so if you either need support for PHP versions prior to 5.3, or need to support PHP versions that have a broken CRYPT_BLOWFISH.