note 106846 added to function.crypt
| From: | dylan at kanux dot org | Date: | Sun, 11 Dec 2011 19:53:14 +0000 |
| Subject: | note 106846 added to function.crypt | ||
| Groups: | php.notes | ||
| Request: | Send a blank email to php-notes+get-185051@lists.php.net to get a copy of this message | ||
I've seen lots of misunderstanding of how to properly generate, store, and verify passwords, so
I put together this detailed example:
<pre>
<?php
// get the current time, so the encryption time can be displayed later
$start_time = microtime(1);
/* account creation/update */
// a new password is provided -- this should never be stored on a server, so generate a hash to
store instead
$correct_password = 'abc123';
// this is the default way to one-way encrypt (ie. hash) a password (this is probably the best
option, unless you need more security)
$stored_password = crypt($correct_password);
// using a more expensive hash makes passwords harder to crack
// ... the salt here is generated by makeSalt() (defined below), which defaults to blowfish
//$stored_password = crypt($correct_password, makeSalt());
// and here is SHA-512
//$stored_password = crypt($correct_password, makeSalt(20, '$6$rounds=%d000$%s$'));
// the cost of crypt() is a tradeoff: ease of cracking passwords vs. server load
echo "\n\n real time = ".round(microtime(1)-$start_time,5)." secs \n\n";
// the hashed password/salt could be stored in a database text column in a 'users' table,
for example
echo "\n\n stored password = $stored_password \n\n";
if (strlen($stored_password) < 60) echo "\n\n WARNING: password hash is too short for
blowfish, the salt params are probably invalid \n\n";
/* login attempt */
// a password was provided -- we want to check if the attempted password matches the previously
stored password, but without knowing $correct_password
$try_password = 'abc1234';
// $stored_password is retrieved (eg. find the password in the database, for a provided username)
// if the stored password matches the hash of the attempted password (using the stored salt), then
the attempted password matches the original
$login_result = $stored_password == crypt($try_password, $stored_password) ? 'OK' :
'FAIL';
// ... return to the login form with an error: invalid password
echo "\n\n $try_password: $login_result \n\n";
// when the correct password is provided, the hashes match
$login_result = $stored_password == crypt($correct_password, $stored_password) ? 'OK' :
'FAIL';
// ... logged in: store the username in a session, etc
echo "\n\n $correct_password: $login_result \n\n";
// generates a random salt for crypt(), defaulting to blowfish (and based on getSalt() below)
function makeSalt( $hash_cost=0, $hash_format='$2a$%02d$%s$',
$salt_length=CRYPT_SALT_LENGTH,
$salt_chars='./aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789' ) {
if (!$hash_cost) $hash_cost = date('y')-2; // default cost is based on the current year
$last_char = strlen($salt_chars)-1;
$salt = '';
for ($i = 0; $i < $salt_length; $i++)
$salt .= $salt_chars[mt_rand(0,$last_char)];
return sprintf($hash_format, $hash_cost, $salt);
}
?>
</pre>
Note: To verify against a stored hash, you should pass the entire stored hash as the
'salt' param of crypt. The hasher() function is incorrect because '$strength'
(ie. cost param) is subject to change, but after such a change, previously generated hashes should
still be verified using the same params from which they were generated. hasher() would fail if any
hashing params are changed, whereas crypt() uses the params which were stored with the hash.
----
Server IP: 66.207.199.35
Probable Submitter: 67.55.13.117
----
Manual Page -- http://www.php.net/manual/en/function.crypt.php
Edit -- https://master.php.net/note/edit/106846
Del: integrated -- https://master.php.net/note/delete/106846/integrated
Del: useless -- https://master.php.net/note/delete/106846/useless
Del: bad code -- https://master.php.net/note/delete/106846/bad+code
Del: spam -- https://master.php.net/note/delete/106846/spam
Del: non-english -- https://master.php.net/note/delete/106846/non-english
Del: in docs -- https://master.php.net/note/delete/106846/in+docs
Del: other reasons-- https://master.php.net/note/delete/106846
Reject -- https://master.php.net/note/reject/106846
Search -- https://master.php.net/manage/user-notes.php