Jump to content

CRYPT_BLOWFISH and supplied string length


Go to solution Solved by Jacques1,

Recommended Posts

I've been using PHP's crypt function to hash passwords, and specifically using the CRYPT_BLOWFISH hash type. I see where it is the salt, delimited by dollar signs that tells PHP how to hash the password.

 

$2y$ at the beginning of the salt says to use CRYPT_BLOWFISH, unless on an older version of PHP, and then it's $2a$ or $2x$.

 

The cost parameter comes next, and setting that is easy, just a number between 04 and 31.

 

Next the docs say to have a string that is 22 characters, from the alphabet "./0-9A-Za-z". It does mention that characters outside this range will cause crypt to return a zero length string. What it doesn't say is if more than 22 characters can be supplied. It also doesn't mention if the dollar sign at the end is mandatory.

 

Oddly enough, the example that the PHP docs gives has more than 22 characters (26):

if (CRYPT_BLOWFISH == 1) {
    // usesomesillystringforsalt is actually 26 characters
    echo 'Blowfish:     ' . crypt('rasmuslerdorf', '$2a$07$usesomesillystringforsalt$') . "\n";
}

So, what is the deal here? Can I supply 32, 64, etc.? Is it just truncated by PHP? It isn't returning a zero length string when I use 32.

Is there some reason you are not using the password_hash function?

 

The server requirements for this application allow for PHP 5.3+. Also, password_hash is just a wrapper for crypt, so this shouldn't be an issue.

  • Solution

Trust me, it's not “just a wrapper”. Even the original author of the password API got it wrong a couple of times, because the crypt() function is weird as hell and had several bugs in different PHP versions.

 

Unless you've actually inspected the C source code, read through the bugtracker and fully understand how bcrypt works, it's just dangerous to use crypt() directly.

 

The salt is not an arbitrary string, and the manual is very misleading. What the crypt() function actually expects is a sequence of 128 random bits generated with a CSPRNG and encoded with a special Base64 variant (not the usual Base64). If you fail to provide a valid salt, pretty much anything can happen.

 

And that was the easy part.

  • How do you get a proper CSPRNG accross all PHP versions and operating systems?
  • Are you aware of the bcrypt input limitations (no more than 56 bytes, no null bytes)? How do you enforce that? Note that strlen() may either return the number of bytes or the number of characters, depending on whether it has been overloaded by the Mcrypt extension.
  • Are you aware of the various error representation and output bugs? How do you validate the resulting hash?
  • How do you prevent timing attacks when you compare the calculated hash with the expected hash?
  • ...

I strongly recommend you use a library which has already gone through this like password_compat.

  • Like 3
This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.