More about passwords

In my previous post I said that proper password hashing is not harder to code than MD5 and here I’m going to demonstrate that. Here’s how it works:

 

1
2
3
4
5
6
7
8
9
10
11
//calculate hash from cleartext $password
$hash = password_hash($password, PASSWORD_BCRYPT, array('cost' => 12));
//now store it in database

//when registered user wants to log in
if(password_verify($password, $hash){
    //OK, password is valid
}
else{
    //wrong password
}

This is it in its simplest form. The second argument here specifies the algorithm used. PASSWORD_DEFAULT uses bcrypt and it will change over time, so the hash string length might change. PASSWORD_BCRYPT uses CRYPT_BLOWFISH and it will always produce 60 character long hash, however it will only process first 72 characters of the input and discard the rest. Optional third argument specifies salt and cost. If salt is omitted, random salt will be generated and stored in the hash string. This is intended mode of usage. The beauty of password_hash() is that it stores algorithm and cost in the hash, so you don’t have to worry about these things when you are using password_verify()

Cost is more interesting option, it specifies the cost in terms of CPU cycles needed to calculate the hash. Values must be in range of 04-31 and this is logarithmic (base 2) scale, meaning that each step is 2 times slower (as you go up) or slower (as you go down). Default value for cost is 10, which is good baseline value, but you should experiment with your server to see what suits you. Here’s a simple benchmark test:

1
2
3
4
5
$start = microtime(true);
$hash = password_hash('test', PASSWORD_BCRYPT, array('cost' => 11));
$end = microtime(true);
$time = $end - $start;
echo "Elapsed time: $time\n";

I also spoke of password entropy. Entropy is a measure of password strength expressed as base 2 logarithm of the number of guesses it would take to break the password. For example 30 bit password has 230 possible combinations. So, how do you calculate this, most calculators don’t base 2 log and how do you calculate password strength in the first place?

Password strength is calculated as the number of characters in the character set used raised to the power of password length. So, if we use password with 8 characters and it has lowercase letters and numbers, password strength is (26+10)8. This is theoretical value assuming that the password is random, which is never the case, but that’s another story. Base 2 log of number N is easily calculated by using base 10 log or natural logarithm (ln) like this: log10(N)/log10(2), or ln(N)/ln(2).

And finally, here’s snippet of jQuery code I use on my Numbers Relay Page to calculate password strength on registration. This gives only an approximate value.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var password = $('#regPassword').val(); //grab password from the form
var chBase = 0; //initialize counter to 0
if(password.match(/[a-z]/g)){
    chBase += 26; //if password contains lowercase letters increase counter by 26
}
if(password.match(/[A-Z]/g)){
    chBase += 26;  //the same for uppercase letters
}
if(password.match(/[0-9]/g)){
    chBase += 10; //digits
}
if(password.match(/[^a-zA-Z0-9]/g)){
    chBase += 32;  //standard US keyboard has 32 non-alphanumeric characters
}

var entropy = Math.round(Math.log(Math.pow(chBase, password.length)) / Math.log(2));

If you want to find out more about this topic I suggest you start with an excellent Wikipedia article.

Read More