Jump to content

Blowfish with salt security


EchoFool

Recommended Posts

Hey

 

 

I have been reading about creating and storing hashes from blowfish in PHP, but am confused by the salt aspect.

 

 

It says it can generate it's own ? But then surely when a user inputs their password to check against the database it will use a new salt each time and thus they won't match up when checking... say on a login screen.... this confuses me greatly..

 

 

Is it just wiser to have a fixed string of numbers to use for the salt all the time instead of letting it generate it's own ?

Link to comment
Share on other sites

It says it can generate it's own ? But then surely when a user inputs their password to check against the database it will use a new salt each time and thus they won't match up when checking... say on a login screen.... this confuses me greatly..

The generated salt can be easily extracted from the string returned by blowfish, so storing that return value effectively stores both the hashed password and the salt.

 

Consider this example:

<?php
$hashed = crypt('abc123');
echo $hashed . "\n";
$hashed2 = crypt('abc123');
echo $hashed2 . "\n";
$hashed3 = crypt('abc123', $hashed);
echo $hashed3 . "\n";

You'll notice that the first two differ because they have different salts, however the first and the third are the same because in the third call crypt uses the salt that was generated by the first call.

 

Is it just wiser to have a fixed string of numbers to use for the salt all the time instead of letting it generate it's own ?

No, you should not (intentionally) use the same salt for multiple users.  This mostly defeats the purpose of using a salt.

Link to comment
Share on other sites

crypt() doesn't just return a hash of the input + salt, it returns a string that has a bunch of information packed into it, including, at a minimum, the algorithm type, salt and hashed value.  The exact format of the string and the information it contains varies from algorithm to algorithm.  For blowfish, $hashed in my example would contain four things: an identifier for the blowfish algorithm, the number of rounds run to generate the hash, the salt and finally the actual hash itself.

 

On a similar note, the $salt parameter of crypt() isn't actually just the salt.  It needs to be a specially formatted string that contains, at a minimum, the algorithm type and salt.  Again, the exact format depends on the algorithm.  The fact that the $salt parameter and return value of crypt are compatible formats is the reason my first example works.

 

Another example:

echo crypt('abc123', '$2a$04$saltsaltsaltsaltsaltxx');

The salt in this example is the base64 value of the string "saltsaltsaltsaltsaltxx$$"

 

This gives you the output:

$2a$04$saltsaltsaltsaltsaltxuK2.MS4sJd6ZjnuS0fp2eenjndo.g4hS

 

You can see how the salt is embedded directly in the output, and how the salt parameter that I passed to crypt() is in the same format as the value that crypt() returned back to me.  In both the $salt parameter and the return value of crypt():

$2a$ tells crypt that this is blowfish

04$ tells crypt how many rounds to use

saltsaltsaltsaltsaltxx / saltsaltsaltsaltsaltxu is the salt value (more on why this differs in a moment)

uK2.MS4sJd6ZjnuS0fp2eenjndo.g4hS is the hashed password

 

One last point of potential confusion is the fact that the final "x" from the original salt appears to be missing and I've listed the "u" that replaced it as belonging to both the salt and the hash in the returned string.  This is because crypt() + blowfish uses a 16 byte (128 bit) hash, but saltsaltsaltsaltsaltxx is 132 bits.  The final four bits of the last 'x' are truncated, not returned by crypt() and thus not present in the returned version of the hash.  For this reason, using "saltsaltsaltsaltsaltxy" as your salt will give you exactly the same output as using "saltsaltsaltsaltsaltxx", but using "saltsaltsaltsaltsaltxA" will give you a different value.

 

It is possible to extract the first 16 bytes of the original salt from the value returned by crypt(), but this is not something you'll probably ever need to do unless you happen to be writing your own implementation of crypt.

Link to comment
Share on other sites

So something like this?

No, the dot is not a separator character.  The salt and the hashed password are concatenated together and then base64 encoded.  A dot happens to be one of the characters used for base64 encoding, so it could show up anywhere in the string.

 

The only way to separate them is to first extract the salt+hash encoded string from the value returned by hash, which always follows the third $, then base64 decode that, and then extract the first 16 bytes as the salt and the remainder as the hash.  At that point you will have two strings of raw binary values which will not render well as ASCII, you would have to base64 encode them again to display them as ASCII.  The primary complication with this is that crypt() uses a different base64 encoding alphabet than PHP's base64_encode and base64_decode functions, so you cannot use them for that part of the process.

 

Also i didn't get the same output as you ... i got:

Your system is not using blowfish for some reason and is instead falling back on what looks like standard DES.

Link to comment
Share on other sites

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.