I'm trying to make register and log in forms having salt encryption, and I'm not really familiar with it. So everything is working except that log in can't recognize password so I'm pretty sure it's encryption problem. These are lines for register:
$hash = hash('sha256', $password1);
function createSalt()
{
$text = md5(uniqid(rand(), true));
return substr($text, 0, 3);
}
$salt = createSalt();
$password = hash('sha256', $salt . $hash);
and these are for login:
$userData = mysql_fetch_array($result, MYSQL_ASSOC);
$hash = hash('sha256', $userData['salt'] . hash('sha256', $password) );
if($hash != $userData['password'])
{
echo "Incorrect password";
}
Can anybody point the problem. Thanks!
Actually your code should work as far as i can see, though it is very unsafe!
Problem: SHA256 is not appropriate to hash passwords, because it is ways too fast. Use a slow key-derivation function like BCrypt.
Problem: A three character salt with only letters is nearly no protection.
Maybe your database field is smaller than 64 characters, or you are comparing different passwords. In every case there is an easier and safer way to hash passwords, just use the new functions password_hash() and password_verify(). There exists also a compatibility pack for earlier PHP versions.
// 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);
There are quite a few things wrong with this. For starters: Are you storing the salt with the password? If not, then passwords become unverifiable.
Security considerations:
hash('sha256', ... is insufficient; consider bcrypt, scrypt, or pbkdf2
https://github.com/DomBlack/php-scrypt
http://us2.php.net/password_hash
https://defuse.ca/php-pbkdf2.htm
$text = md5(uniqid(rand(), true)); Ever heard of openssl_random_pseudo_bytes()?
(Also, you shouldn't seek to decrypt passwords, only verify them.)
If you're not familiar with these concepts, play it safe and use a tried and true library.
Related
I'v googled around for way to do this properly and there's just a lot of variations on how to do so. So i've come up with this and wouldn't mind some critique and links to better practices.
// Register Form - User providese username(email) password(text) //
So i grab the data:
$user = mysql_real_escape_string($_POST['user']);
$pswd = mysql_real_escape_string($_POST['pass']);
$salt = hash( 'sha256', microtime() . rand() );
$encrypt = hash( 'sha256', $pswd . $salt );
Then insert into database user_email | encrypted_pass | salt
// Login Form - User providese username(email) password(text) //
So first based on user(email) i grab encrypted_pass and salt info. Then,
$user = mysql_real_escape_string($_POST['user']);
$pswd = mysql_real_escape_string($_POST['pass']);
$encrypted_pass_fromDB = $var['encrypted_pass'];
$salt_fromDB = $var['salt'];
if (hash( 'sha256', $passwrd . $salt_fromDB) === $encrypted_pass_fromDB)
{
echo "GOT IT!";
}
I've read bcrypt is a better option, but for now i want to understand the SALT method better. Also, when i use $options = ['cost' => 11,]; i get an error Parse error: syntax error, unexpected '[' but that's a separate issue i guess. Used code based on PHP salt and hash SHA256 for login password
Any comments are appreciated! Thanks!
The only thing that you are protected against when adding a salt to your hash is the use of huge tables of pre-computed hashes called "Rainbow Tables". These have not been a major problem in quite some time, though because:
Rainbow tables containing extended character sets are massive, some requiring upwards of 16GB of RAM to search.
Parallelized bruteforce cracking across multiple computers, or offloaded to cloud services like AWS are faster, cheaper, and makes the addition of simple salts virtually inconsequential.
Better algorithms hash the password thousands of times and apply the given salt in a cryptographically "proper" way to make it more difficult to crack. However, the hashing algorithms that they are based on like SHA and MD5 are designed to be small and fast, and bruteforcing them requires large amounts of CPU time, which is cheap and easy to parallelize.
Bcrypt is different. It uses the Blowfish algorithm which requires relatively large amounts of RAM, which is expensive, and thus difficult to parallelize. This is why everyone recommends it so strongly.
TL;DR Hashing is better than plaintext, salted is better than unsalted, bcrypt is miles better than pretty much everything else out there so frickin use it.
You should use the built in crypt function:
http://php.net/crypt
You have two options:
Let PHP Crypt generate the salt
$user = mysql_real_escape_string($_POST['user']);
$pswd = mysql_real_escape_string($_POST['pass']);
//Salt is generated automatically
$encrypt = crypt( $pswd );
Generate the Salt yourself
$user = mysql_real_escape_string($_POST['user']);
$pswd = mysql_real_escape_string($_POST['pass']);
//These are the settings for the salt (Separated so you can understand it)
$algorithm = "2a";
$length = "12";
//Start the salt by specifying the algorithm and length
$salt = "$" . $algorithm . "$" . $length . "$";
//Add on random salt and make base64 adjusted for bcrypt's version
$salt .= substr( str_replace( "+", ".", base64_encode( mcrypt_create_iv( 128, MCRYPT_DEV_URANDOM ) ) ), 0, 22 );
//Encrypt with your generated salt
$encrypt = crypt( $pswd, $salt );
Verifying it is easy:
if ( $encrypted_pass_fromDB_with_salt === crypt( $passwrd, $encrypted_pass_fromDB_with_salt ) ) echo "ok";
PHP offers now such an easy way to generate safe password hashes, that we should use it, have a look at the function 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);
Of course it is good to understand how a salt works (and how difficult it is to handle it correctly), so try it out but use the function above for your life system.
I am having problems login users in using the below code.
It seems like when I execute my if statement with the correct user password the password entered by the user and the password in my database are not matching up. Can someone give me their input on what I am doing wrong?
$pwd = hashed password in my database
$pass = password users enter on logi page
if ($pwd === PwdHash($pass,substr($pwd,0,9))) {
function PwdHash($pwd, $salt = null)
{
if ($salt === null) {
$salt = substr(md5(uniqid(rand(), true)), 0, SALT_LENGTH);
}
else {
$salt = substr($salt, 0, SALT_LENGTH);
}
return $salt . sha1($pwd . $salt);
}
Can someone give me their input on what I am doing wrong?
Not to offend you, but you're literally doing everything wrong. Let's start right at the beginning:
$salt = substr(md5(uniqid(rand(), true)), 0, SALT_LENGTH);
This is a very poor way to calculate a salt. Right from the rand man page:
This function does not generate cryptographically secure values, and should not be used for cryptographic purposes.
Right there alone, your whole mechanism falls apart. Security is only as good as its weakest component. But it doesn't stop there. uniqid() creates a unique id, however the main problem with this is that it is based on the current time. Having a unique salt is good, but since it is strictly time-based, it makes it predictable, which is very bad and far outweighs the benefits of having it unique.
Next, you md5 the salt. This adds absolutely nothing in terms of security and it could possibly be debated that it actually reduces security due to md5 collisions.
Now on to how you're hashing your password:
$salt . sha1($pwd . $salt);
Sha1 is very fast, and is therefore a very bad choice for password hashing. Doing salt . fastHash(password . salt) is simply security by obscurity and is not security at all.
So what should you be doing?
First step: STOP rolling your own password hashing mechanism and leave it in the hands of experts who are smarter than you and I.
Second step: Use password_hash. If you don't have PHP 5.5 check the comments on that page for a compatibility library compatible with earlier versions. It's as simple as doing:
$hash = password_hash("someAmazingPassword", PASSWORD_DEFAULT);
Then see password_verify() for verifying the hashes.
You should put SALT_LENGTH to your checking function as you do in your generator function. .
Manually cheking are they different or the same?
I have created this code for a salt and pepper password encryption. I assume this is a good way to encrypt passwords, but what level of encryption is this?
I first thought the 'bit' part was the length of characters used but I know that is incorrect. How many bits of encryption would this be?
PHP
function _h() {
$result = "";
$charPool = '0123456789abcdefghijklmnopqrstuvwxyz';
for($p = 0; $p<32; $p++)
$result .= $charPool[mt_rand(0,strlen($charPool)-1)];
return md5(sha1(md5(sha1($result))));
}
$salt = _h();
$pepper = _h();
$pass = $salt.md5($salt.md5($_POST['password']).$pepper).$pepper;
UPDATE
I understand this is not encryption, so I would not be able to say this is encrypted, but instead hashed. Is a hashed password with a salt and pepper secure enough to save a password?
There are quite a lot of problems with your scheme to hash a password.
PHP 5.5 will have it's own functions password_hash() and password_verify() ready, to simplify generating BCrypt password hashes. I strongly recommend to use this excellent api, or it's compatibility pack for earlier PHP versions. The usage is very straightforward:
// 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);
These functions will solve following problems:
They use a slow adaptable hash function (BCrypt), MD5 is ways too fast for hashing passwords.
They generate a safe salt from the random source of the operating system.
A pepper is not just a second salt, in contrast to a salt, the pepper is secret and will not be stored together with the hash. The same pepper will normally be used for all passwords.
There is no use in complicating the computation of salt and $peppr too much. After all the task is not the retrieval of what was originally used to produce these spices but trather the value of $_POST('a'] and you give away the $saltand $pepper as prefix/suffix (otherwise you couldn't use the stored valuelater to verify an input password with this hash). That being said, do as #zneak commented and use an expert library function.
Before I start I'd like to apologise for bringing up this subject once again, as many users did, but with a research I did, I wasn't happy with what I've found. I just hope to come up with something really helpful here.
Since md5 or sha1 are considered bad practice (even when using salts ???), I have tried to create this function for hashing my password
$password = $_POST['password']; // lets say that my password is: my_sercretp#ssword123
function encrypt_the_password($password){
$salt = "lorem_ipsumd0l0rs1t#m3tc0ns3ct3tur#d1p1sc1ng3lit";
return hash('sha256', $salt.$password);// can use also different algorithm like sha512 or whirlpool
}
$hashed_password = encrypt_the_password($password);
Note that this one I use it in a personal website with only one user, me. In case of having more than one users I come up with something like this:
$password = $_POST['password'];
function generate_salt() {
$salt = uniqid(md5("lorem_ipsumd0l0rs1t#m3tc0ns3ct3tur#d1p1sc1ng3lit".microtime()));
$salt = hash('sha256', $salt);// can use also different algorithm like sha512 or whirlpool
return $salt;
}
function encrypt_the_password($password,$salt){
return hash('sha256', $salt.$password);// can use also different algorithm like sha512 or whirlpool
}
$hashed_password = encrypt_the_password($password,generate_salt());
Is this secure enough (in each case) or can this improved more???
MY EDIT: I tried to come up with something new using the crypt() function. Here's my code in case of having a site with only one user, admin:
$password = $_POST['password'];
$salt = "L0r3mIpsUmD0l0rS1tAm3t";
$hashed_password = crypt($password', '$2a$12$' . $salt);
and in case of having a site with more than one users:
$password = $_POST['password'];
function generate_salt() {
$salt = uniqid(sha1("L0r3mIpsUmD0l0rS1tAm3tc0ns3CT3tur4d1p1sc1ng3lit".microtime()));
$salt = substr(sha1($salt), 0, 22);
return $salt;
}
$hashed_password = crypt($password', '$2a$12$' . generate_salt());
Is this ok or needs improvements???
Improve it by not making up your own algorithm. Your algorithm is insecure because your salt is constant and you only hash with one iteration of SHA256, which is computationally cheap.
Instead, use Bcrypt, which is both computationally expensive and verified by people who know what they're doing, so it's much safer than your solution.
You should use the password functions that will come inbuilt in PHP 5.5. There's a fallback library by ircmaxell that can provide the functions in earlier versions of PHP: https://github.com/ircmaxell/password_compat
It will always use the most recent hashing technique available, and in case even update the records for you. Make sure you read the README coming along with this library.
Do not make your own hashing function.
$salt = uniqid();
$crypt = md5($password , $salt);
$new_pass = $crypt.':'.$salt;
In the database: ot÷„[ªà%Ûʼn¹:17b8bc731c322c9e05a26666458117f4
Is this a syntactical error? Or is the database not set up with the correct character formatting?
You enabled raw_output
PHP DOC
If the optional raw_output is set to TRUE, then the md5 digest is instead returned in raw binary format with a length of 16.
Change
$crypt = md5($password , $salt);
^------ You moved the salt to raw_output
To
$crypt = md5($password . $salt);
^------ Should be this
For security reasons i would not advice you to use md5 for password hashing. MD5 is so badly broken that it no longer takes so long to find an appropriate collision or reverse hash. Once broken, a hash algorithm only gets worse, never better therefore it would be better to choose an unbroken hash algorithm.
Standard
sha1
hash (sha256 & sha512)
Better Alternatives
password_compat
Portable PHP password hashing framework
PBKDF2