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
}
Related
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 want my login password to be secured. So I came up to use the PHP's crypt() function to hash the password before inserting it to database. But Im having trouble when comparing the user input password from the converted hash password. Here's my code:
<?php
$password = 'hello_password';
# A higher "cost" is more secure
$cost = 10;
# Create a random salt
$salt = strtr(base64_encode(mcrypt_create_iv(16, MCRYPT_DEV_URANDOM)), '+', '.');
# Blowfish algorithm.
$salt = sprintf("$2a$%02d$", $cost) . $salt;
$salted_password = $password . $salt; // apply salt to password
# hash the password
$hash_password = hash('sha256', $salted_password);
$userInput = 'hello_password'; // suppose this is the user input password
if (hash('sha256',$userInput) == $password) {
echo "Password Verified.";
}
else {
echo "Incorrect Password";
}
?>
But it always displays Incorrect Password although my password is correct. I don't want to use "hash_equals" function as it is not supported with my current PHP version. Can someone help me with this ? Thanks
You're comparing a hashed user input to the actual user password. So of course this is never going to work.
You're basically asking if hash == 'hello_password'. A hash will never match that, that is the whole point of a hash. You also aren't using the salt with the user input.
You hash the actual password with a salt which is fine:
$salted_password = $password . $salt; // apply salt to password
# hash the password
$hash_password = hash('sha256', $salted_password);
So you need to hash the user input with the salt, the same way:
$salted_input = $userInput . $salt; // apply salt to user input
# hash the input
$hash_input = hash('sha256', $salted_input);
Then you can compare $hash_input with $hash_password.
You also aren't using a salt properly. The salt is supposed to be used in the storage of the password to prevent rainbow table attacks. Randomly generating a salt to apply to both the input and the password at the time of comparison is pointless.
I am storing a username and an encrypted password in a mysql database. For testing only, I am also storing the password in an unencrypted form in the database as well.
In the following code, I get the hashed password and the unencrypted password from the database. I then encrypt the unencrypted password.
The given password does not pass the password verification test for the stored hash or the new hash.
The stored password does pass the password verification test for both the stored hash and the new hash.
The call to strcmp says that the stored password and the given password are equal.
How could this be?
[edit] : I am passing in $password from user input on the web page.
// get hashed password from database
$sql = "SELECT member_password FROM member WHERE member_username=:username;";
$stmt = $db->prepare($sql);
$stmt->bindParam("username", $username);
$stmt->execute();
$hash = $stmt->fetch(PDO::FETCH_ASSOC);
$hash = $hash["member_password"];
// get unencrypated password from database
$sql = "SELECT member_unencrypted FROM member WHERE member_username=:username;";
$db = getConnection();
$stmt = $db->prepare($sql);
$stmt->bindParam("username", $username);
$stmt->execute();
$unencrypted = $stmt->fetch(PDO::FETCH_ASSOC);
$unencrypted = $unencrypted["member_unencrypted"];
// encrypt the unencrypted password that was retrieved from the database
$encrypted = password_hash($unencrypted, PASSWORD_DEFAULT);
// given password does not pass the new hash per this test
if(password_verify($password, $encrypted))
echo '<br>given password passed new hash';
else
echo '<br>given password did not pass new hash';
// stored password does pass the new hash per this test
if(password_verify($unencrypted, $encrypted))
echo '<br>stored password passed new hash';
else
echo '<br>stored password did not pass new hash';
// given password does not pass the stored hash per this test.
if(password_verify($password, $hash)){
echo '<br>given password passed stored hash';
else
echo '<br>given password did not pass stored hash';
// stored password does pass the stored hash per this test.
if(password_verify($unencrypted, $hash))
echo '<br>stored password passed stored hash';
else
echo '<br>stored password did not pass stored hash';
// stored and given passwords are equal per this test.
if(strcmp($unencrypted, $password))
echo '<br>stored and given passwords are equal';
else
echo '<br>stored and given passwords are not equal';
Output:
given password did not pass new hash
stored password passed new hash
given password did not pass stored hash
stored password passed stored hash
stored and given passwords are equal
It is not clear from your question where the variable $password is coming from, and if it contains the same text as the one stored in the database.
If you make such tests you must be aware that the function password_hash() will generate a unique salt and includes it in the resulting hash. For verification you need this salt (and other parameters) to get a comparable hash-value. That means the hash will be different each time and if you call password_hash() twice, you end up with different salts and non-compareable hashes.
I tried to explain the hash format in another answer.
[edit from Bruce: see comments for the answer]
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.
I'm trying to hash the password if you sign up on my website, but it doesn't work.
This is my code to hash the password upon signing up:
$escapedName = mysql_real_escape_string($_POST['user']);
$escapedPW = mysql_real_escape_string($_POST['password']);
$salt = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));
$hashedPW = hash('sha256', $escapedPW . $salt);
Then I just insert it in a database (the hashed password and the salt).
For example, when I hash Sas, with the following salt:
abac7ad23185ad19967f0d13e962197962782f0b7ec32d9889c27a93a9e800fa
This is the hashed password:
8ca5c5f31fafbf382533dbcbfc22b3635d776ec7770c7eac58d8ef9f1fa3613c
But when I try to hash the password on log in, with the exact same password and salt, this becomes the hashed pass:
6eb4b16444f18cee19db32bd29a39970e3019c5b1972a982ae4cb9a59642dffc
This is the code I use to login:
$escapedName = mysql_real_escape_string($_POST['user']);
$escapedPW = mysql_real_escape_string($_POST['password']);
$saltQuery = mysql_query("SELECT salt FROM members WHERE user='{$escapedName}'");
while($result = mysql_fetch_assoc($saltQuery)) {
$salt = $result['salt'];
}
$hashedPW = hash('sha256', $escapedPW . $salt);
$sql = mysql_query("SELECT * FROM members WHERE user='$escapedName' AND pass='$hashedPW'; ");
while ($res = mysql_fetch_assoc($query2)) {
$username = $res['user'];
$PW = $res['pass'];
}
I hope it's not too much code and I also hope you will understand my question.
Sorry I can't comment but something tells me that there is a length restriction on the salt column in your database.
Example: The salt field might only allow a 64 characters while the generated salt might be longer therefore when you save the salt it gets trimmed which ultimately changes the hashed password.
If that's the case, you might want to trim the salt before saving it.
I'd advise using PDO to make queries against your database.
Your inputs to the hash function must be different for some reason or other.
Add log output messages that print your inputs before you hash for both use cases (create user and login). Also be sure to put quotes around the inputs in your logging to show whitespace issues.
Compare the raw inputs as well as the output of the hash function in both cases, and there will be a difference somewhere. If there is no difference, and the output of the hash is the same, then there is a problem in your query that is looking up the user in the login case.
Whatever you're doing, it's insecure if you WANT the hashes to be the same! See http://php.net/crypt for proper password hashing.
All you need:
function check_password($password) {
...//get db password to compare
if (crypt($post_password, $db_results[0]['password']) == $db_results[0]['password']) {
return true;
} else { return false; }
}