15 if (!function_exists(
'random_bytes')) {
21 function random_bytes($length)
24 $buffer_valid =
false;
25 if (function_exists(
'mcrypt_create_iv') && !defined(
'PHALANGER')) {
26 $buffer = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
31 if (!$buffer_valid && function_exists(
'openssl_random_pseudo_bytes')) {
33 $buffer = openssl_random_pseudo_bytes($length, $strong);
34 if ($buffer && $strong) {
38 if (!$buffer_valid && @is_readable(
'/dev/urandom')) {
39 $file = fopen(
'/dev/urandom',
'r');
42 while ($read < $length) {
43 $local_buffer .= fread(
$file, $length - $read);
44 $read = PasswordCompat\binary\_strlen($local_buffer);
47 if ($read >= $length) {
50 $buffer = str_pad($buffer, $length,
"\0") ^ str_pad($local_buffer, $length,
"\0");
52 if (!$buffer_valid ||
PasswordCompat\binary\_strlen($buffer) < $length) {
53 $buffer_length = PasswordCompat\binary\_strlen($buffer);
54 for (
$i = 0;
$i < $length;
$i++) {
55 if (
$i < $buffer_length) {
56 $buffer[
$i] = $buffer[
$i] ^ chr(mt_rand(0, 255));
58 $buffer .= chr(mt_rand(0, 255));
66 if (!defined(
'PASSWORD_BCRYPT')) {
73 define(
'PASSWORD_BCRYPT', 1);
74 define(
'PASSWORD_DEFAULT', PASSWORD_BCRYPT);
75 define(
'PASSWORD_BCRYPT_DEFAULT_COST', 10);
78 if (!function_exists(
'password_hash')) {
89 function password_hash($password, $algo, array $options = array())
91 if (!function_exists(
'crypt')) {
92 trigger_error(
"Crypt must be loaded for password_hash to function", E_USER_WARNING);
95 if (is_null($password) || is_int($password)) {
96 $password = (string) $password;
98 if (!is_string($password)) {
99 trigger_error(
"password_hash(): Password must be a string", E_USER_WARNING);
102 if (!is_int($algo)) {
104 "password_hash() expects parameter 2 to be long, " . gettype($algo) .
" given",
111 case PASSWORD_BCRYPT:
112 $cost = PASSWORD_BCRYPT_DEFAULT_COST;
113 if (isset($options[
'cost'])) {
114 $cost = (int) $options[
'cost'];
115 if ($cost < 4 || $cost > 31) {
117 sprintf(
"password_hash(): Invalid bcrypt cost parameter specified: %d", $cost),
126 $required_salt_len = 22;
127 $hash_format = sprintf(
"$2y$%02d$", $cost);
133 sprintf(
"password_hash(): Unknown password hashing algorithm: %s", $algo),
138 $salt_req_encoding =
false;
139 if (isset($options[
'salt'])) {
140 switch (gettype($options[
'salt'])) {
146 $salt = (string) $options[
'salt'];
149 if (method_exists($options[
'salt'],
'__tostring')) {
150 $salt = (string) $options[
'salt'];
157 trigger_error(
'password_hash(): Non-string salt parameter supplied', E_USER_WARNING);
163 "password_hash(): Provided salt is too short: %d expecting %d",
170 } elseif (0 == preg_match(
'#^[a-zA-Z0-9./]+$#D', $salt)) {
171 $salt_req_encoding =
true;
174 $salt = random_bytes($raw_salt_len);
175 $salt_req_encoding =
true;
177 if ($salt_req_encoding) {
180 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
182 './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
184 $base64_string = base64_encode($salt);
185 $salt = strtr(rtrim($base64_string,
'='), $base64_digits, $bcrypt64_digits);
187 $salt = PasswordCompat\binary\_substr($salt, 0, $required_salt_len);
189 $hash = $hash_format . $salt;
191 $ret = crypt($password, $hash);
193 if (!is_string($ret) ||
PasswordCompat\binary\_strlen($ret) != $resultLength) {
202 if (!function_exists(
'password_get_info')) {
220 function password_get_info($hash)
224 'algoName' =>
'unknown',
225 'options' => array(),
228 $return[
'algo'] = PASSWORD_BCRYPT;
229 $return[
'algoName'] =
'bcrypt';
230 list($cost) = sscanf($hash,
"$2y$%d$");
231 $return[
'options'][
'cost'] = $cost;
238 if (!function_exists(
'password_needs_rehash')) {
251 function password_needs_rehash($hash, $algo, array $options = array())
253 $info = password_get_info($hash);
254 if ($info[
'algo'] !== (
int) $algo) {
258 case PASSWORD_BCRYPT:
259 $cost = isset($options[
'cost']) ? (int) $options[
'cost'] : PASSWORD_BCRYPT_DEFAULT_COST;
260 if ($cost !== $info[
'options'][
'cost']) {
270 if (!function_exists(
'password_verify')) {
280 function password_verify($password, $hash)
282 if (!function_exists(
'crypt')) {
283 trigger_error(
"Crypt must be loaded for password_verify to function", E_USER_WARNING);
286 $ret = crypt($password, $hash);
293 for (
$i = 0;
$i < PasswordCompat\binary\_strlen($ret);
$i++) {
294 $status |= (ord($ret[
$i]) ^ ord($hash[
$i]));
297 return $status === 0;
305 if (!function_exists(
'PasswordCompat\\binary\\_strlen')) {
319 function _strlen($binary_string)
321 if (function_exists(
'mb_strlen')) {
322 return mb_strlen($binary_string,
'8bit');
324 return strlen($binary_string);
339 function _substr($binary_string, $start, $length)
341 if (function_exists(
'mb_substr')) {
342 return mb_substr($binary_string, $start, $length,
'8bit');
344 return substr($binary_string, $start, $length);
356 if (is_null($pass)) {
357 if (function_exists(
'crypt')) {
358 $hash =
'$2y$04$usesomesillystringfore7hnbRJHxXVLeakoG8K30oukPsA.ztMG';
359 $test = crypt(
"password", $hash);
360 $pass = $test == $hash;