Understanding how salt is generated/used in bcrypt password_hash - php

I am working on an existing Symfony 2.8 web app project that uses FOSUserBundle for user authentication.
In addition to the web front end the users can use different smartphone client to connect to the web app using a REST API. Thus the users need to be authenticated both when logging in directly in the web app and when connecting why the REST API.
Until one of the latest FOSUserBundle updates a bcrypt password hash and the used salt where stored in the database.
When connecting using the REST API, the salt is transferred to the client to locally hash the password using the same salt. The hashed password is than send back to the web app for authentication.
I know that sending the hashed password instead of plain text does not add (a lot of) additional security, since the communication is only possible using HTTPS. However this is the way the clients work: They need the salt to generate the hashed password. I can update the clients in the future, but right now this is just the way the work.
The Problem:
They way FOSUserBundle hashes the password has changed: Since it is considered to be saver to NOT specify the salt manually but to let PHP generate the salt automatically (in PHP 7 it is not even possible to manually set the salt), a manual salt is no longer supported.
This is no problem when logging into the web app directly, but since the REST clients still need a salt, this updates breaks the REST connection.
Is there any way to combine both methods? Let PHP create the salt automatically, extract and send this salt to the clients?
As far as I understand the salt is stored with the hash in the same string:
However, simply copy the 21 char salt from the hash-string and send these to the clients does not work. It seems that these 21 chars a enough to test/verify the password, but not to re-create the hash. Is this correct?
So, is there any solution to use PHP password_hash without setting a salt, and to get to know the used salt at the same time?
EDIT 1:
To answer #RiggsFolly question: MD5 was not used at any time. It is not correct, that bcryp/password_hash will not create the same hash twice. It will do so, if both the password and the salt are the same:
$s = 'password';
$salt = 'salt5678901234567890123456789012';
$options['salt'] = $salt;
$h1 = password_hash($s,PASSWORD_BCRYPT,$options);
$h2 = password_hash($s,PASSWORD_BCRYPT,$options);
echo $h1 . PHP_EOL;
echo $h2 . PHP_EOL;
Result:
$2y$10$salt56789012345678901uTWNlUnhu5K/xBrtKYTo7oDy8zMr/csu
$2y$10$salt56789012345678901uTWNlUnhu5K/xBrtKYTo7oDy8zMr/csu
password_hash will create a new hash for the same password, if the salt is not specified. This is because, the salt will be created randomly which is than of cause different on each call.
EDIT 2:
As one can see in Edit 1, using a salt with 32 chars will result in a string that only includes the first 21 chars of the salt. However this salt-prefix cannot be used to re-create the same hash since it is too short to be accepted.
However, if the prefix is filled up with 0, it seems to work:
$s = 'password';
$salt = 'salt5678901234567890123456789012';
$salt_prefix = 'salt5678901234567890100000000000';
$h1 = password_hash($s, PASSWORD_BCRYPT, array('salt' => $salt));
$h2 = password_hash($s, PASSWORD_BCRYPT, array('salt' => $salt_prefix));
echo $h1 . PHP_EOL;
echo $h2 . PHP_EOL;
So a solution could be:
let FOSUserBundle use password_hash to create the hash without manually specifying a salt.
extract the salt from the result string and pad it with 0 to a length of 32 chars
pass this salt to the client
Can anyone confirm, that this a real solution and not just some coincidence ?

You seem to misunderstand how password hashing and salts are supposed to work.
The salt is never sent to the client. It is generated (or manually specified) only once when the password is created. Its purpose is to randomize the output of the hash function, so that when the database gets into the wrong hands it is not possible to get users passwords by comparing the output to rainbow tables.
When the user uses his password to login the password is sent from the client to the server unhashed (but usually over https). The password comparing function then fetches the stored hash+password, gets the salt from it, appends the salt to the user input, calculates the hash and then compares that to the hash from the database.
Maybe the project you're on has a bad implementation of salts. In fact, one of the reasons using manual salts is discouraged is to prevent things like this.
So a solution could be:
let FOSUserBundle use password_hash to create the hash without
manually specifying a salt.
extract the salt from the result string and pad it with 0 to a length
of 32 chars
pass this salt to the client
Can anyone confirm, that this a real solution and not just some
coincidence ?
This is not a good solution. The only good way is to make sure password hashing is implemented the right way so you don't have to generate the salt more than once.

The salt is, as documented on http://us2.php.net/crypt, 22 characters and not 21.
<?php
$key = 'password';
$hash = password_hash($key, PASSWORD_BCRYPT);
$salt = substr($hash, 7, 22);
$rehash = password_hash($key, PASSWORD_BCRYPT, ['salt' => $salt]);
if ($hash == $rehash) {
echo 'ok', PHP_EOL;
}
The last 2 in the salt5678901234567890123456789012 salt changing to an u is just some magic in crypt blowfish.

Let client provide any salt. Or server gives a random salt it has never used. Treat the hash as the raw password. Re-hash the hashed password and rest stuff.

Related

php password_hash, random/static salt and user auth

ive been reading up about the php 5.3+ password_hash - but have a few questions, plz excuse me if im being daft. Seems 1 big catch point for making strong user password hashes is using random salts as opposed to static ones. If im checking a user logging in, surely I have to somehow have a copy of the salt used (stored in db) to check? If thats the case, do i use a secure salt function (bcrypt salt functions) and store that string in the db (and recreate with each new login) or what?
I have this:
$options = [
'cost' => 11,
'salt' => mcrypt_create_iv(22, MCRYPT_DEV_URANDOM),
];
When i echo $options['salt'] I get odd characters which i prob couldnt store in a db. Im used to the old (insecure) method of storing a random salt in the db and using that (statically) for user login auth, but the dynamic/random salt is throwing me off a bit. What am i missing? The random salt changes each time, so if i stored it now, and the user re-logged in the hash would be different so the db password wouldnt match the posted one..??
Thanks~
Seems 1 big catch point for making strong user password hashes is using random salts as opposed to static ones.
Random salts are the default behavior of both PHP 5.5's password_hash() and the userland implementation, password_compat.
If im checking a user logging in, surely I have to somehow have a copy of the salt used (stored in db) to check?
The salt is included in the password hash itself. There is no need to store it separately.
The random salt changes each time, so if i stored it now, and the user re-logged in the hash would be different so the db password wouldnt match the posted one..??
That's the responsibility of the password_verify() method. From the PHP docs:
Note that password_hash() returns the algorithm, cost and salt as part of the returned hash. Therefore, all information that's needed to verify the hash is included in it. This allows the verify function to verify the hash without needing separate storage for the salt or algorithm information.
EDIT: Password Verification and Random Salts
I think I understand where your confusion is coming from. Hopefully this will help explain password hashing, verification, and the part played by random salts.
If you look at the source of password_compat (https://github.com/ircmaxell/password_compat/blob/master/lib/password.php), you'll see that both password_hash() and password_verify() make use of PHP's crypt() function. When you create a password with password_hash(), you store it and never pass that password through password_hash() again. The algorithm, cost, and salt are all returned with the hash. Example:
$options = array('salt' => 'ThisIsTheSaltIProvide.');
$hash = password_hash('password', PASSWORD_DEFAULT, $options);
// $hash = $2y$10$ThisIsTheSaltIProvide.EcCQwybvWB3iNxIv9FwsPJEWhR/ywZ6
We could have created the same hash by using crypt directly, which is precisely what password_hash() does behind the scenes.
$hash = crypt('password', '$2y$10$ThisIsTheSaltIProvide.');
// $hash = $2y$10$ThisIsTheSaltIProvide.EcCQwybvWB3iNxIv9FwsPJEWhR/ywZ6
The hash consists of:
Algo information: $2y$ (BLOWFISH)
Cost param: 10
An extra $
The salt: ThisIsTheSaltIProvide.
Using that information, password_verify() reproduces the hash and then compares it to the persisted hash, like so:
$existingHash = $2y$10$ThisIsTheSaltIProvide.EcCQwybvWB3iNxIv9FwsPJEWhR/ywZ6
$testHash = crypt('password', '$2y$10$ThisIsTheSaltIProvide.');
// if $existingHash and $testHash match, then the password is good
A new, additional salt never comes into play.
Additionally, using RANDOM salts is important. If everyone used the same salt, then users with the same password would also have the same hash. No one wants that.

Md5 salt password php

I know that there are alots of questions about this subject but i really need to ask this.
Today I've been working on encrypting passwords with md5.
So what I've done is.
I got 4 salts. (they changes depending on user values)
from email id and substr then md5 them
from email and id substr other positions
a long string, substr it and then md5 it
another long string, substr it and then md5 it
Then i md5 salt1 and 3 and the password with salt 2 and salt4
After this I have to change the password automatically whenever a user changes his email or his id getting changed.
What do you guys think about this?
Nothing.
MD5 is broken and bad.
Using the mailaddress as salt is a good idea. But using md5 is not. Use instead bcrypt, scrypt or pbkdf2.
Don't invent your own ecryption, unless you really know what you are doing, and trust me, you don't
First, let us define a few terms.
Encryption is when you encode a message so that it cannot be read. Encryption involves a plaintext, a cipher and a key. It is like putting a book (the plaintext) in a locked room (cipher), which can only be opened using a known tool (a key). There are many kinds of encryption, but that is a simple description. Encryption is two-way, meaning that you can encode and decode the message.
Cryptographic hash is when you take any kind of data and generate a fixed size value for it (usually called a hash or a digest). Cryptographic hashes are one-way, which means that you cannot reverse the process.
A salt is a unique string, or a collection of bits, similar to a nonce (a unique number that is only used once). Salts are only used to make it infeasible for a cracker to process a list of hashes. They are not supposed to be used as a secret (i.e. like a cryptographic key). The only reason people usually talk about randomness when it comes to salts is because they want to generate a unique salt (if the randomness is not great enough they may get colliding salts, for instance).
Okay, now to how you should hash a password.
A relatively safe way of hashing a password is to simply tack on a unique hash onto a password, and then save the salt with the password:
$pass = 'this is my password';
$salt = uniqid('', true);
$hash = sha1($pass . $salt);
// INSERT INTO users ('hash', 'salt') VALUES ('$hash', '$salt') WHERE ...
That is an okay way of doing it if your website does not retrieve any sensitive data from its users.
If you deal with sensitive data, or if you just want to make sure that you are doing everything you can to keep stuff safe, then there is a PHP function that does the hashing for you. It is called crypt() (read the documentation to learn how it works). Here is an example of how to hash a password using the function:
$pass = 'this is my password';
$salt = 'unique string';
$hash = crypt($password, '$2y$07$'.$salt.'$');
echo $hash;
That will securely hash a password.
The thing to realize is that the crypt() function is much more secure than anything you can come up with (unless you are a specialist in the area).
In newer versions of PHP (5.5.0+) there is a password hashing API that makes it even simpler to hash a password.
There are also various hashing libraries out there. PHPass is a popular one.
It is bad, because it uses MD5.
MD5 is a very fast operation. It can be executed billion of times per second on graphic cards hardware. It is considered bad practice to use it for any password related things.
Use bcrypt. Use a random salt. Use the upcoming PHP API for hashing, verifying and rehashing passwords. This include file implements it for versions starting with PHP 5.3.7: https://github.com/ircmaxell/password_compat
Well, "MD5 is broken and bad" is a little exagerated. Even if it can be brute-forced with a lot of CPU, it is not "broken" and is still a very useful algorithm for a lot of things involving hashing.
So "MD5 should not be used for password encryption" sounds much better to me.
When using PHP, an easy and safe option is to rely on the password_hash() (which natively generates a random salt) and password_verify() functions.
The advantage is that the encryption algorithm will transparently be updated with each new PHP version (at the moment PASSWORD_DEFAULT is set to bcrypt, but should bcrypt be "broken" it can be set to a newer algorithm), which makes any code using those functions quite resilient.
I personally do not recommend involving of the user id and his email into the hashing of his password.
You can deal with the password by:
Dynamic salt per user based on random string generated on user registration
Prepend one part of the salt and append the other around the password
Double md5: md5(md5($password))
Etc.
a simple way would be to generate a random salt for each user and hash your password like this
public function encodePassword( $raw, $salt ) {
return hash('sha256', $salt.$raw);
}
For high security hash, you can check this link which explain how to implement PBKDF2:
http://crackstation.net/hashing-security.htm#phpsourcecode

Salting passwords PHP, MySQL

Is the following a good way to salt passwords?
hash('sha256', $_POST['password'], $_POST['email'])
I am using the user email as a salt. Some people do not use emails, some others say to use a random number.
Even if I use a random number then I will still need to store it on my MySQL table, so the salt will still be known anyway, and with the added benefit of using emails is that the possibility of rainbow tables is greatly decreased, even if I was to use a 16-bit integer?
The idea behind a salt is to prevent a hacker from using a rainbow table. For instance, if the hacker is able to compromise your database and figure out what the hashed password is he can't easily reverse engineer the hash to find a value that would generate the same hash.
However, there exist tables of already hashed words called rainbow tables. Some people have already gone through the trouble of calculating the hash of every word in the dictionary and other common passwords. If the hacker has one of these tables, plus the hashed password from your database, it makes it very easy to figure out what the password is.
However, a salt changes all that because now, instead of hashing the password, you are hashing the password plus some random value which means that the rainbow table is now useless. It does not matter if the hacker can compromise the salt.
It is perfectly fine to save the salt in clear text. You want to use something that is not uniform across all users either because, again, that defeats the purpose. I personally like to use the timestamp the account was created.
Does that make sense?
What happens if a user changes his email address? You won't be able to verify his/her password anymore because the salt value will be gone.
You shouldn't use anything as a salt that is likely to change over time. Generate a random salt (long enough to defeat rainbow tables) and use it together with the password to generate the hash.
Right now the best possible solution to use in PHP for password hashing is to use the bcrypt (blowfish) implementation. Why? There are several reasons:
variable 'work' parameter
built-in salt
Keep in mind that if you are not running php 5.3, then crypt_blowfish may not be available on your system.
Work Parameter
Blowfish/crypt is already has an expensive setup time but by setting the work factor you can increase the amount of time it takes to calculate a hash. In addition, you could easily change that work factor in the future as computers get faster and are able to compute hashes more easily. This makes the particular hashing method scale.
Built-in Salt
For me this is just laziness but I like that the salt & pass are stored together.
Implementation
To use blowfish you'd create a hash as follows
// salts must be 22 characters
$salt = "ejv8f0w34903mfsklviwos";
// work factor: 04-31 (string), each increase doubles the processing time.
// 12 takes my current home computer about .3 sec to hash a short string
$work = '12';
// $2a$ tells php to use blowfish
// you end up with a string like '$2a$12$mysalthere22charslong'
$options = '$2a$' . $work . '$' . $salt;
$hashedPass = crypt($plaintext, $options);
To verify a hashed password is simplicity:
if(crypt($user_input, $stored_password) == $stored_password) { echo "valid!"; }
Now, if at any given time you want to increase the work factor you could take the submitted pass after a successfull login, and rehash and save it. Because the work factor is saved along with the salt & password, the change is transparent to the rest of the system.
Edit
There seems to be some confusion in the comments about blowfish being a two way encryption cypher. It is not implemented as such in crypt. bcrypt is an adaptive password hashing algorithm which uses the Blowfish keying schedule, not a symmetric encryption algorithm.
you can read all about it here: http://www.usenix.org/events/usenix99/provos.html
or you can read even more about using bcrypt (the hashing implementation of blowfish) here: http://codahale.com/how-to-safely-store-a-password/
i suggest using iteration such as below. The crypt could be replaced with md5 or any other hashing algorithm. the 10 could be any number.
$pass=mysql_real_escape_string($_POST['pass']);
$iterations = 10;
$hash = crypt($pass,$salt);
for ($i = 0; $i < $iterations; ++$i)
{
$password = crypt($hash . $pass,$salt);
}
In addition, you could add any other variable. I hope this solve the problem
You could use this:
$salt='whatever';
$a=hash('sha256', $_POST['password'], $salt);
$b=hash('sha256', $_POST['email'], $salt);
$hash=$a.'-'.$b;
When the user changes the email, just do:
$old_a=substr($old_hash,0,strpos($old_hash,'-'));
$new_b=hash('sha256', $_POST['email'], $salt);
$new_hash=$old_a.'-'.$new_b;

What encryption method is used on these passwords?

I am working on a program that needs to know what is used to encrypt passwords in the application Tigerpaw 11. Tigerpaw 11 uses SQL so I can see the encrypted password I am just not sure what particular encryption method is used.
I changed one of the users passwords several times so I had some examples for you guys.
For what it helps this is what I know about the application:
- Ties to MS SQL for all data
- Seems to be written in a .NET language
Samples:
123456, 6df7a625c514577b8ce73af649e3c179
MyPassword, ec46ca799923b1a6ffab6b5cb75d059a
CrackIt, b4df19b23f1882e4d0a42e2451443628
They seem to have some kind of hash value based on user. For this instance it could be "Tim Way" or 50 amongst other fields.
The end result is I want to be able to do user authentication in PHP against this password.
They are probably not encrypted but hashed, the fact that the 'encrypted passwords' are all the same length should have given you a clue. Common hashing functions are MD5 or SHA1.
The passwords are not encrypted, but hashed. Your hashes seem to be hashed with the MD5 hashing function. Probably a secret salt is used to make guessing common passwords harder.
It appears that they are using salt in there hash.
Salt is a somewhat secret term used change the hash value. I doubt they would want to tell you the salt.
you can see the results from many popular hashing algos here
http://www.insidepro.com/hashes.php?lang=eng
It's probably a MD5 hash of the password and user name (and/or user ID, if that exists). Also check if there is something else related to the row in the user database table that might also influence the hash. For example, when setting the same password to the same user produces different hashes then there probably is something like a SALT value (a random value or string that changes with each password update).
Given these values you have to guess how they are being combined. If you're unlucky, then they might even use separators and such.
I'd try with
md5($username . $password);
md5($userID . $password); // assuming there is a numeric user ID too
md5($password . $username);
md5($password . ":" . $username); // separator example
md5($username . $password . $salt) // if there is any
Any any other combination that comes to your mind. Good luck.
It looks like md5 hash salted with username and secret key (sha1 is 40 chars long).
This is reviving an old thread however as of version 14 encryptions have been converted to AES256
I know this applies to credit card details, Not sure if it applies to passwords, They are likely just a hash as per previous answers.

Going from unsalted to salted MD5 passwords

I have a LAMP (PHP) website which is becoming popular.
I played it safe by storing the user passwords as md5 hashes.
But I now see that's not secure; I should have salted the md5 hash - because it's currently possible to decode unsalted md5 hashes using rainbow tables.
What can I do?
I don't want to make everyone type a new password.
You can do a "2 step hashing" instead of creating a hash in a single step.
You could append each password hash to the username, and then hash it again. This will create an undecryptable hash thats salted with unique informations.
The usual process of salting is
salt+PWD -> hash
You could do something like:
PWD -> Hash -> UserID+Hash -> Hash
(Note the UserID was only picked so a unique salt for each double hash exists... Feel free to make your salt more complex)
You can salt them on the fly. Add a piece of code so that, when someone logs in, it does the normal process (computes the MD5 sum of the password and checks it against the stored hash) and if that succeeds, recompute a salted version of the hash from the clear-text password they entered, and store it in the password file.
The only wrinkle is that you'll need to add an indicator for whether each MD5 is salted or not, since you'll have a mix of both for a while. Or, for a minor loss of security, you can check each password salted and unsalted and if either one hits, accept the login. Of course, if you detect that it was unsalted, then you upgrade at that point.
The answer is simple, make sure the keep a record or some sort of flag of which users have passwords on the new system of hashing, when they next login, authenticate them, calculate the new hash, flip the flag.
Now whenever someone logs in and the flag is set, authenticate them with the new hash.
Why not add a new column new_pwd to your user table, which stores the result of md5($originallyHashOfPwd . $salt). You can then precompute new_pwd and once that's done adjust your login checking to compare the result of md5(md5($entered_pwd) . $salt) to what's in new_pwd. Once you're done switching your login checking, delete the old column.
That should stop rainbow-table style attacks.
You can still use a salt. Just calculate another hash from the current hash together with a salt:
$newHash = md5($salt.$oldHash);
For new passwords you then need to use:
$hash = md5($salt.md5($password));
A great way to update the passwords while also making them more secure is to change to using a salted SHA1 for passwords. A SHA1 is harder to create a collision against, and it also has a different string length to MD5. A MD5 is 32 characters long, while a SHA1 is 40 characters long.
To convert these in PHP, you first check the string length of the stored password. If it is 32 characters long, check the password using your old method and afterwards, write a new one using SHA1 to the database.
If I remember correctly, this is precisely how WordPress handled this issue.
Dynamically re-encrypt the passwords when the users log in the next time, i.e. first check whether it’s correct, afterwards encrypt it with a salt and store it again.
You can migrate the passwords by adding a column in your tables to store the new format.
When a user logs in successfully, if the new column is empty, put the stronger password in there and empty out the original column. If the new column has an entry, compare the input to the value in there.
Two options here
Decode the passwords yourself, and re-encode them with a salt (I recommend something a little more fancy than MD5). You should inform the users that you're viewing their passwords unencrypted. It'll probably take a lot of time as well.
Make them retype their passwords, and store those salted and encrypted.
As far as I can see, there is no other way of recovering the passwords.
EDIT:
Although MD5 is a hash and should not be decodable, it can be broken using rainbow tables: with probability almost one, you can find a unique (here's the probability) string of at most, say, 20 characters with a given hash, especially if your character set is limited, say, to alphanumeric. Strictly speaking, this is not decoding. For all practical purposes, it is.
Extra note: producing the rainbow tables, and looking up 1000 password is still going to take a lot of time.
Salt the original hash as mentioned by others. Just a few pointers here:
Salts are better the longer they are. Also if they contain more then just [a-z0-9] but length is better first of all.
If someone already has a copy of your DB and you rehash the same passwords with salt, the rehash the old hash with salt will not work. Instead you really should force users to make a new password.
You should match new passwords (and passwords to be salted) up against various lists of the most commonly used passwords. These are used in "brute force" attacks. Prompt/force the user to change the password.
If you're moving away from MD5, you should go skip simply salting and go to an even better technique called stretching. In particular you should use bcrypt (implemented as PHPASS with php).
Here is a great link on why bcrypt: http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html
And here is a short How To:
1. Download the phpass package: http://www.openwall.com/phpass/
2. Look at test.php for examples like the one below:
require 'PasswordHash.php';
$t_hasher = new PasswordHash(8, FALSE);
$correct = 'plaintextpassword';
$hash = $t_hasher->HashPassword($correct);
$check = $t_hasher->CheckPassword($correct, $hash);
If $check===true (which is the case above) then the password is correct.
If your password is 'hello', you would hash it using HashPassword, put the hash in a database, and when a user logs in, call CheckPassword(userenteredpassword,hashInDb) to see if the password is correct
sadly, your only way is to tell your users to renew their passwords.
you could also generate random passwords, but that is the same hassle.
edit
you could just double encode your stored passwords. so your new salted hashing algorithm would be:
md5(md5($new_password).$salt).':'.$salt
to update your old passwords use
md5($old_password.$salt).':'.$salt
to check if a provided password is correct simply use
list($stored_password, $salt) = explode(':', $salted_password);
if(md5(md5($provided_password).$salt) == $stored_password) {
// you are now logged in
}

Categories