18

I know PHP 5.5 is in alpha but this class I am making is just being made in advance to utilize it's hashing feature by using function_exists().

I checked out the password_hash documentation. The 3rd argument is for $options which currently supports two options, 'salt' and 'cost'.

It states the following:

cost, which denotes the algorithmic cost that should be used. Examples of these values can be found on the crypt() page.

When I go to the crypt() page the documentation it gives is:

Blowfish hashing with a salt as follows: "$2a$", "$2x$" or "$2y$", a two digit cost parameter, "$", and 22 digits from the alphabet "./0-9A-Za-z". Using characters outside of this range in the salt will cause crypt() to return a zero-length string. The two digit cost parameter is the base-2 logarithm of the iteration count for the underlying Blowfish-based hashing algorithmeter and must be in range 04-31, values outside this range will cause crypt() to fail. Versions of PHP before 5.3.7 only support "$2a$" as the salt prefix: PHP 5.3.7 introduced the new prefixes to fix a security weakness in the Blowfish implementation. Please refer to » this document for full details of the security fix, but to summarise, developers targeting only PHP 5.3.7 and later should use "$2y$" in preference to "$2a$".

I can't seem to get my head wrapped around this. It says PHP 5.3.7 and later should use $2y$, but what cost value do I use to get that one and is it the best value to choose? The example they provide uses a value of 7, but according to the above it can go up to 31, what difference does it make to use say 4 opposed to say 31?

Salman A
  • 262,204
  • 82
  • 430
  • 521
kittycat
  • 14,983
  • 9
  • 55
  • 80
  • 1
    Until you can find a reason to choose something other than the default values, (like when the defaults are demonstrably weak) why not just choose the default values and move on to the next issue? In my experience, the PHP default values for everything have gotten a lot better since PHP 5.3. Just a thought, ~Ray – Ray Paseur Dec 16 '12 at 22:24
  • @RayPaseur, true. However, that still does not shed light onto how and why to specify different cost values. The PHP default may be secure, but at the minimum for possibly performance reasons. So depending on the production environment and security policy it may require something stronger. Just my thoughts. =o) – kittycat Dec 16 '12 at 22:36
  • Also see Openwall's [Portable PHP password hashing framework](http://www.openwall.com/phpass/) (PHPass). Its hardened against a number of common attacks on user passwords. And it estimates a cost based on the selected hash (but I'm not sure if the option is exposed). – jww Oct 11 '14 at 23:30

2 Answers2

18

The function password_hash() is just a wrapper around the function crypt(), and shall make it easier to use it correctly. It takes care of the generation of a safe random salt, and provides good default values.

The easiest way to use this function would be:

$hash = password_hash($password, PASSWORD_DEFAULT);

That means, the function will hash the password with BCrypt (algorithm 2y), generates a random salt, and uses the default cost (at the moment this is 10). These are good default values, particularly i would not recommend generating the salt of your own, it is easy to make mistakes there.

Should you want to change the cost parameter, you can do it like this:

$hash = password_hash($password, PASSWORD_BCRYPT, ["cost" => 11]);

Increasing the cost parameter by 1, doubles the needed time to calculate the hash value. The cost parameter is the logarithm (base-2) of the iteration count, which means:

$iterations = 2 ^ $cost;

Edit:

I missed the point, that you want to generate your own class. For PHP version 5.3.7 and later, there exists a compatibility pack, from the same author that made the password_hash() function. You can either use this code directly, or look at the well crafted implementation. For PHP versions before 5.3.7 there is no support for crypt with 2y, the unicode aware BCrypt algorithm. You can instead use 2a, which is the best alternative for earlier PHP versions. I did an example with a lot of comments, maybe you want to have a look at it too.

P.S. The expressions "salt" and "cost factor" are used correctly in password_hash(), the crypt() function though, uses the word salt for all crypt parameters together, that's a bit misleading.

xxweltew
  • 3
  • 3
martinstoeckli
  • 23,430
  • 6
  • 56
  • 87
1

Disclaimer: this is with PHP 5.3.10, but it seems not really different from your description.

The cost applies to the cost of computation. When you increase the cost value, it takes longer to hash the password

function blowfish_salt($cost)
{
    $chars = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    $salt = sprintf('$2y$%02d$', $cost);
    for ($i = 0; $i < 22; ++$i)
        $salt .= $chars[rand(0,63)];

    return $salt;
}

$password = 'My perfect password';
$cost = $argv[1];
$salt = blowfish_salt($cost);
$hash = crypt($password, $salt);

When I run this on my (old) machine as

php mycrypt.php 10

it returns immediately (~0.2 sec), whereas with

php mycrypt.php 16

it takes about 5.2 seconds.

Kris
  • 1,388
  • 6
  • 12
Olaf Dietsche
  • 72,253
  • 8
  • 102
  • 198
  • What would the benefits of increasing it be, other than making it more time consuming to brute crack the data, when should it be increased, and what would a sane value be? Thanks =o) – kittycat Dec 16 '12 at 22:42
  • 1
    @cryptic That's the main reason. For a user it's simply annoying, if he must wait longer for a registration or login. But for an attacker it makes a huge difference, whether he can test 50 passwords/sec or 1 password/5 sec. Although when 7 is the default, I think 15 or even 10 might be excessive as a cost factor. – Olaf Dietsche Dec 16 '12 at 22:46
  • @OlafDietsche this (comments) was the question/anwser that I was looking for, and I think this information should be more easy to find, as in I've been searching what the `cost` value does in terms of increased security and/or inconvenience. cheers. – Martin Oct 20 '15 at 10:55