Hashing: PHP Crypt() not working correctly - php

I am having a strange behavior with the crypt() . Here is my code in Zend:
$correct_password_hash = $this->getHelper('User')->generateHash('bd468cffe6b179d8e5ef30bd993d37e5','572906092501a20f4222a54.54479708');
$edited_password_hash = $this->getHelper('User')->generateHash('bd468cffe6b179d8e5ef30bd993d37e','572906092501a20f4222a54.54479708');
echo "Correct Password Hash - ".$correct_password_hash."<br/>";
echo "Edited Password Hash - ".$edited_password_hash;
I am passing a md5 generated string to the helper function generateHash as first parameter and a salt as second parameter. I store the generated hash in $correct_password_hash variable.
Now in in the second call to the same helper function , i have just removed the letter 5 at the end of the first parameter. the second parameter is the same. But still its generating the same hash as first one.
Here is the output:
Correct Password Hash - 57CO1Lzyk81kk Edited Password Hash - 57CO1Lzyk81kk
The helper generateHash is as follows:
public function generateHash($md5, $salt)
{
return crypt($md5, $salt);
}
Is this how crypt() supposed to work?
Thanks.

crypt() is defaulting to standard DES-based algorithm. Which in turn uses only 8 first characters from the password and 2 first characters from the salt.
See crypt() documentation for more details about how to modify the behaviour of crypt():
http://php.net/crypt
If you are doing password hashing, go with bcrypt.

Related

How can password_verify and doveadm pw -t verify a password without salt

im currently trying to understand hashes and salts. As i understand it, it should not be possible to verify a password, if i only have the password and the generated hash(that was generated with a random salt ofc).
So how can the password_verify function in PHP verify my password, if i dont give it the salt? Is there a hidden variable in the background, that stores it for the php hashing functions?
And if that is the case, how can
doveadm pw -t '{SHA512-CRYPT}$6$myhash...' -p "qwertz"
verify it too, even if i run it on a complety different computer? Thats a tool, that comes with Dovecot(a MDA).
Here is my PHP code, that creates a random salt with 64 chars, combines it with a password, creates a hash and verifies the hash via password_verify().
I just started working on the whole hash/salt/pepper thing today, so there could be a huge flaw in my whole train of thought.
<?php
$password = "qwertz";
$salt = createSalt(64);
$hash = crypt($password, "$6$$salt");
if (password_verify($password, $hash)) {
echo 'Password is valid!';
} else {
echo 'Invalid password.';
}
function createSalt($length){
$chars = "IrhsYyLofUKj4caz0FDBCe2W9NRunTgQvp7qOXmS5GM3EJV6i8tAHdkPbxwl1Z";
$salt="";
for($i=0; $i < $length; $i++){
$newchar = substr($chars, rand(0,strlen($chars)-1),1);
$salt .= $newchar;
}
return $salt;
}
?>
The hash contains several pieces of information. This article explains the format used by Unix but I believe PHP password functions use a similar format (if not the same):
The hash field itself is comprised of three different fields. They are
separated by '$' and represent:
Some characters which represents the cryptographic hashing mechanism used to generate the actual hash
A randomly generated salt to safeguard against rainbow table attacks
The hash which results from joining the users password with the stored salt and running it through the hashing mechanism specified in
the first field
It can also include the exact per-algorithm options used to generate the hash, such us the algorithmic cost:
var_dump(password_hash('foo', PASSWORD_BCRYPT, [
'cost' => 8,
]));
string(60) "$2y$08$7Z5bTz7xXnom8QsrbZ7uQetMLxOZ7WjuDkUYRIh73Ffa17GV1Tb7q"
Here $2y$08$ means that Bcrypt with cost 8 was used.
If we use the newer Argon2 available in PHP/7.2 there're even more params:
$argon2i$v=19$m=1024,t=2,p=2$YzJBSzV4TUhkMzc3d3laeg$zqU/1IN0/AogfP4cmSJI1vc8lpXRW9/S0sYY2i2jHT0
Some backgrounds to the answer from #Álvaro González :
PHP manual suggests using "password_hash" instead of "crypt" function through "password_hash" is a "crypt()" wrapper ( Because, it uses a strong hash, generates a strong salt, and applies proper rounds automatically. )
"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 "password_verify" function to verify the hash without needing separate storage for the salt or algorithm information. : http://php.net/manual/en/function.password-verify.php
Since, "password_hash" is a wrapper for "crypt", "crypt" also does the same, ie., returns the algorithm, cost, and salt as part of the returned hash. and thus "password_verify" can verify the hash.
Now, please check the answer given by #Álvaro González

I can't compare password from my database and the one inputted

I am using php crypt function to make a password secure, but when I try and compare a password entered to a one in the database it will not work.
here is my code to create the password in the first place:
$crypt_password = crypt($_POST['confirm-password']);
here is me trying to compare to the password in another function:
$input_crypt_password = crypt($_POST['input-pw']);
if ($input_crypt_password == $dbpassword){
// do change password function
}
This is not working.
when i print both passwords the are different.
why are the passwords different even though I am entering the same password and using crypt function on both?
can anyone point me in the right direction?
From the docs
Example #1 crypt() examples
<?php
$hashed_password = crypt('mypassword'); // let the salt be automatically generated
/* You should pass the entire results of crypt() as the salt for comparing a
password, to avoid problems when different hashing algorithms are used. (As
it says above, standard DES-based password hashing uses a 2-character salt,
but MD5-based hashing uses 12.) */
if (hash_equals($hashed_password, crypt($user_input, $hashed_password))) {
echo "Password verified!";
}
?>
The code in the question will effectively generate a new hash every time it's called - the existing password hash needs to be passed as the salt to get a consistent result.
As also mentioned in the docs:
Use of password_hash() is encouraged.
I'd go further and say you definitely should be using password_hash instead of calling crypt for password usage (assuming php >= 5.5); in any case though for whichever whatever tools/methods you're using - please read the docs to know how to use them.
Don't use crypt directly for passwords.
If you have PHP 5.5+, than use the built in password_hash function, otherwise if you have PHP 5.3.7+ use the polyfill for this function.
Try to something like this.
$crypt_password = crypt($_POST['confirm-password'],salt);
$input_crypt_password = crypt($_POST['input-pw'],salt);
if ($input_crypt_password == $dbpassword){
// do change password function
echo "Password match successfully!";
}
Here salt parameter to base the hashing on. If not provided, the behaviour is defined by the algorithm implementation and can lead to unexpected results.
I don't know what to say that will add more detail than what everyone else has already said...
So, in modern day hash/unhashing algorithms it would be unsafe to store passwords using standard hashing functions (e.g. MD5 / SHA256) as it is quick and easy to unhash this type of entry.
password_hash() as referenced in other answers and comments should be you're #1 way to safely store passwords as it uses a one way hashing algorithm.
You should read this page!
And then in response to your original question, use hash_equals() function to compare passwords.
As many guys here said, you should use password_hash php function.
Here you can see a simple example how to use it:
<?php
$password = '123456';
$userInput = '123456';
$storedHash = password_hash($password, PASSWORD_DEFAULT);
if (password_verify($userInput, $storedHash)) {
echo 'OK';
} else {
echo 'ERROR';
}
Also as mentioned before, if you use older version of PHP, you can install polyfill.
Did you trim the input before saving in db and while making the comparison. Since the input is coming from browser this may be a reason why it is not matching. otherwise this https://stackoverflow.com/a/41141338/1748066 seems appropriate.

Different passwords, same hash check using crypt in php

If i use crypt() to hash a password:
$password = "my_password_12345";
$salt = base64_encode(openssl_random_pseudo_bytes(64, $cstrong));
$crypt = crypt($password, $salt);
I get something like this
echo $crypt; //AG6hHvhjwnqpc
So, when I check for the hash I do this and all work fine
echo crypt($password, $crypt); //AG6hHvhjwnqpc
But why the following happens? I do the same check as above but with a password similar to the previous one and I get the same hash.
$password = "my_password_12345_not!";
echo crypt($password, $crypt); //AG6hHvhjwnqpc
I would expect a different hash, but instead I'm getting the same
In PHP, the crypt function use only the 8 first characters :
Extract from the documentation:
The standard DES-based crypt() returns the salt as the first two characters of the output. It also only uses the first eight characters of str, so longer strings that start with the same eight characters will generate the same result (when the same salt is used).

Confusing PHP BCrypt implementation

I'm trying to find a hashing algorithm to use to save my passwords in the DB (along with a salt). I found this on SO: How do you use bcrypt for hashing passwords in PHP?. The top answer has a library that seems to work. I'm just a bit confused by the verify method.
To run the script, the author of the library provides:
$bcrypt = new Bcrypt(15);
$hash = $bcrypt->hash('password');
$isGood = $bcrypt->verify('password', $hash);
The hash method takes the input string and hashes it using mcrypt + a salt. The result is returned to $hash. Then the verify method takes the same input as hash method + $hash. verify then calls mcrypt + the value of $hash (instead of some random salt) -- and somehow the results are the same $hash???
Simplified:
hash = password + salt
verify = password + hash
verify = hash <-- huh???
What did I miss?
ALSO:
I plan to modify the code such that hash method accepts a $salt parameter. I will make getSalt a public method. This way, I can get a salt, store it in the DB, store the hash in the DB, and use user's input + salt to see if it hashes to what I have stored in the DB. Any problems with this idea?
I'm not familiar with the actual bcrypt, but something along the following lines must be what happens:
When you create the "hash", $bcrypt->hash('password') returns a string that contains both the hash value and the initial salt.
When you subsequently say $bcrypt->verify('password', $mystring), the function first reads the salt part out of your input string, then creates the hash again with that salt, and finally compares that computed hash with the hash part of your input string.
In any salinated hashing scheme, you will always have to store the salt along with the hash value.
The hash in this case also contains the salt. It's concatenated to the beginning of the string, usually as something like $2a$12$SALT.... Passing the hash to verify is just done to use that salt value again, the rest of the hash is ignored. That also means you do not need to modify the function for use with salts, that's already part of the algorithm.

How do I effectively use crypt()

I don't understand the documentation at php.net. It appears they are using the encrypted version of password as the salt when testing against the original encryption.
When I insert crypt with out the optional second parameter (the salt) I get different encrypted versions of the same password. Is this expected behavior?
However if I insert a second parameter of 'd4' then I get the same encrypted passwords for the same password input. Expected behavior.
Prior to insertion on signup:
$pass = crypt('$pass', 'd4'); // after this I insert $pass into the mysql table
Testing on signin:
$pass = crypt($pass, 'd4'); // after this I test $pass against the mysql table
PHP.net documentation:
<?php
$password = crypt('mypassword'); // let the salt be automatically generated
/* You should pass the entire results of crypt() as the salt for comparing a
password, to avoid problems when different hashing algorithms are used. (As
it says above, standard DES-based password hashing uses a 2-character salt,
but MD5-based hashing uses 12.) */
if (crypt($user_input, $password) == $password) {
echo "Password verified!";
}
?>
How does this work?
Since crypt() only uses the first two characters (or whatever CRYPT_SALT_LENGTH is) of the salt argument, passing in the encrypted password (of which the first characters are the salt originally used to encrypt it) does the right thing.
If no salt argument is passed in, a random salt is generated and used.
If your question is... Is it normal that with certain encryption ciphers you are returned with different encrypted strings for the same password/input? The answer is yes. Not to sure what you are refering to about salt. Salt it just salt. In the end it is a deturant and means nothing. Using passwords or encrypted forms of passwords as salt is not recommended, but using some random hash (base64) of a phrase is commonly used. Let me know if this doesn't any, and I'll try again.

Categories