note 106846 added to function.crypt

From: 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

« previous php.notes (#185051) next »