I have problem with password hashing. This is my controller
public function registerUser() {
$valid = Validator::make(Input::all(), array(
'pass' => 'required|min:5',
'pass2' => 'required|same:pass'
));
if($valid->fails()) {
return Redirect::route('register')->withErrors($valid)->withInput();
}
// $password = Input::get('pass');
if(Input::hasFile('photo')) {
$img = Input::file('photo');
if($img->isValid()) {
echo Hash::make(Input::get('pass'));
}else{
return Redirect::route('register')->withInput()->with('errorimg','image-error');
}
}else{
echo Hash::make(Input::get('pass'));
}
//return Redirect::route('register')->with('success','register-success');
}
Everytime I refresh my browser, the hashed pass is always change.
ex : if I put "qwerty" as pass, it should show
$2y$10$PPgHGUmdHFl.fgF39.thDe7qbLxct5sZkJCH9mHNx1yivMTq8P/zi
Generating a different hash every time is on purpose, because the Hash::make() method will generate a random salt. A random salt is necessary to securely protect the user's passwords.
To check an entered password against the stored hash, you can use the method Hash::check(), it will extract the used salt from the hash-value and uses it to generate comparable hashes.
// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = Hash::make($password);
// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = Hash::check($password, $existingHashFromDb);
That's because if you don't give a salt bcrypt creates one every time it hashes something.
Source
Related
I'm trying to use Yii's generatePasswordHash() function, but I get a different hash with the same password, every time.
$this->password = Yii::$app->getSecurity()->generatePasswordHash($this->password);
Here 3 hashes created with the password "test":
$2y$13$wsvC4i8YMwKKHJ2K5iYRG.Z0KBetOh3BctVpJN5pVkXGOcW85hRkO ,
$2y$13$QfV2Qxlj4F5gUh1wIL2WUewoZ55CKYKevjRmRqrenxq8L5ym5xX9. ,
$2y$13$rDArvLa8hnpDGiiDdCs7be4iTsr2T3XMXmnapynuD1i1ekbz8zF4m
Anyone an idea what's happening?
EDIT:
When I try to verify with:
Yii::$app->getSecurity()->validatePassword($password, $this->password)
it returns false.
EDIT#2:
function looks like this:
public function validatePassword($password)
{
return Yii::$app->getSecurity()->validatePassword($password, $this->password);
}
$password is the input password and $this->password is the hash.
Strangely password_verify($password, $this->password) works, but Yii's verifier doesn't.
All hashes are correct. Because hash algorithms make different hashes for the same password. Where does the password variable come from in your code? It should be a password string not a hash.
$hash = "hashed version";
$password = "string password";
if (Yii::$app->getSecurity()->validatePassword($password, $hash)){
// password correct
}
Adding to efendi's answer.
Getting a different hash each time Yii's generatePasswordHash() function is run is normal behavour.
Validating the password against the hash requires the 'salt' from the 'hash'.
The first 22 characters after '$2y$13$' in the hash is the salt.
The validatePassword($password, $hash) function gets the salt from the hash, hashes the $password using the salt which should get the same hash as the $hash if the password were to be correct.
I realize this is not as secure as it could be, but I want to do it this way.
I have this code which generates the password from a user's entry ($password)...
$salt = mcrypt_create_iv(22, MCRYPT_DEV_URANDOM);
$new_password = md5($salt . $password);
$new_password = $salt . $new_password;
This is how I'm trying to check against the saved password:
$split_salt = substr($saved_password, 0, 22);
$incomplete_password = md5($split_salt . $current_password);
$hashed_password = $split_salt . $incomplete_password;
if ($saved_password != $hashed_password) {
$error = "error";
} else {
//Validated
}
As far as I can tell this should work. However, I'm getting the error instead of the validation. Does this have something to do with MCRYPT not producing exactly 22 characters?
I know this is not what you want to hear, but your scheme is so utterly unsafe and a good solution is so simple to implement, that you should reconsider:
// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_DEFAULT);
// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);
Your actual problem is the salt, mcrypt_create_iv() will return a binary string and it can very well contain \0 characters. So it is pure luck if your approach works or not.
i'm sorry for the bad use of English... I'm having a problem with making a function that hashes my password with a salt(first time using a salt).
The problem is that I don't know how to really return the salted/hashed password from the function.
My code:
# Password hashing with a salt.
function hashing($stringPassword)
{
// Making a random uniq code as salt.
$salt = uniqid(mt_rand(), true);
$HASH512 = hash('SHA512', $stringPassword);
$hashPassword = $salt.$HASH512;
return $stringPassword;
}
And how I tried to test it:
<?php
$stringPassword = '482301';
hashing($stringPassword);
echo $hashPassword;
?>
Thank you for helping!
Your code is backwards. The salt has to be part of the password BEFORE you hash it. and then you need to return the hashed password AND the salt, so that you can do proper comparisons later.
function hashing($cleartext) {
$salt = uniqid(mt_rand(), true);
$hash512 = hash('SHA512', $salt . $cleartext);
return(array('hash' => $hash512, 'salt' => $salt));
}
$foo = hashing('letmein');
echo "Salt is: $foo[salt]";
Since you are hashing passwords, you should be aware that the SHA* algorithms are not appropriate to hash passwords. They are much too fast, instead you need a function with a cost factor like BCrypt or PBKDF2 where you can control the necessary time for the calculation.
PHP offers a dedicated function password_hash() to generate BCrypt hashes, for earlier PHP versions you can use the compatibility pack:
// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);
// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);
I have searched through Internet and found the function for hashing the password. But
i'm having trouble to deal with hashed password stored in the the database. the function i'm using generate the random password as it is concatenated with the random generated salt.
the problem comes when a user wants to change his password.
current_password = random hashed password( which must match the one stored in db).
if(current_password == $db_password){
enter new password
}
the above condition wont be true since the password is always random.
my function
function cryptPass($input,$rounds = 9) {
$salt = "";
$saltChars = array_merge(range('A','Z'),range('a','z'),range(0,9));
for($i = 0;$i < 22; $i++){
$salt .= $saltChars[array_rand($saltChars)];
}
return crypt($input,sprintf('$2y$%02d$', $rounds).$salt);
}
$pass = "password";
$hashedPass = cryptPass($pass);
echo $hashedPass;
i have 3 column in my user table (id, username, password).
can any one tell me how to properly use this function,
or is there a best way to do this?
You want to store the $salt generated in the database along with the hashed password. Then when you come to check the password you will be able to get the salt from the database and use it in the hashing process again.
So your database table with have an extra column in it called "salt"
(id, username, password, salt)
You need to do the same steps, as you would for the login. Check if the entered old password matches the password-hash in the database, then create a hash from the entered new password and store it.
PHP already has a function password_hash() to create a hash, and a function password_verify() to check whether the entered password matches the stored password-hash.
// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);
// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);
So your code would look something like this:
if (password_verify(current_password, $db_password))
{
enter new password
}
This is stored in a database. How do I send this demo password to my user? I cant convert this ($2y$10$Zjk5YzQ4ZTlhMzNlNTUzMO3Wnm1FqXmAb6/4DmyptNGoEdWGLwls.) to normal text.
Is there any solution? I'm also unable to send random password.
demo = $2y$10$Zjk5YzQ4ZTlhMzNlNTUzMO3Wnm1FqXmAb6/4DmyptNGoEdWGLwls.
Here are some functions I used for password checking and generation:
function password_encrypt($password) {
$hash_format = "$2y$10$"; // Tells PHP to use Blowfish with a "cost" of 10
$salt_length = 22; // Blowfish salts should be 22-characters or more
$salt = generate_salt($salt_length);
$format_and_salt = $hash_format . $salt;
$hash = crypt($password, $format_and_salt);
return $hash;
}
function generate_salt($length) {
// Not 100% unique, not 100% random, but good enough for a salt
// MD5 returns 32 characters
$unique_random_string = md5(uniqid(mt_rand(), true));
// Valid characters for a salt are [a-zA-Z0-9./]
$base64_string = base64_encode($unique_random_string);
// But not '+' which is valid in base64 encoding
$modified_base64_string = str_replace('+', '.', $base64_string);
// Truncate string to the correct length
$salt = substr($modified_base64_string, 0, $length);
return $salt;
}
function password_check($password, $existing_hash) {
// existing hash contains format and salt at start
$hash = crypt($password, $existing_hash);
if ($hash === $existing_hash) {
return true;
} else {
return false;
}
}
It is not a good scheme for password recovery, to generate a new password and send it to the user. Instead send the user a link with a random independend code, and store this code in your database (hashed). When the user clicks the link, then let him enter a new password. There is no need to know the old password then, the user is authenticated when he can read the email (his email address).
A forgotten password form, can be posted by everybody: You wouldn't be happy if somebody entered your email, and your password was changed immediately. Retrieving the link, you have the opportunity to either ignore the email, or to confirm that you really want to change the password.
As you correctly pointed out, passwords should be stored as hash, and therefore cannot be retrieved. As soon as the hash of the password is stored in the database, there should be no further need to know the real password. Whenever you need the password later, you will know it, because the user entered it.
To generate the BCrypt hash, i would recommend to use the PHP function password_hash(), there exists also a compatibility pack for earlier PHP versions. Especially the generation of the salt is solved much better there.
P.S.
The hash you described is called BCrypt, it is based on the blowfish cipher which is used for two-way encryption.