PHP_INT_MAX - 4) { trigger_error(sprintf('hash_pbkdf2(): Supplied salt is too long, max of PHP_INT_MAX - 4 bytes: %d supplied', $salt_len), E_USER_WARNING); return false; } // @codeCoverageIgnoreEnd // Check $iterations is a positive integer if ($iterations < 1) { trigger_error('hash_pbkdf2(): Iterations must be a positive integer: ' . (int) $iterations, E_USER_WARNING); return false; } // Check $length is greater than or equal to 0 and integer if ($length < 0) { trigger_error('hash_pbkdf2(): Length must be greater than or equal to 0: ' . (int) $length, E_USER_WARNING); return false; } // Type casting $algo = (string) $algo; $password = (string) $password; $salt = (string) $salt; $iterations = (int) $iterations; $length = (int) $length; $raw_output = (bool) $raw_output; $hash_length = $strlen(hash($algo, null, true)); if ($length == 0) { $length = $raw_output ? $hash_length : $hash_length * 2; } $digest_length = $length; if (!$raw_output) { $digest_length = ceil($digest_length / 2); } $block_count = ceil($digest_length / $hash_length); $hash = ''; for ($i = 1; $i <= $block_count; $i++) { $key = $digest = hash_hmac($algo, $salt . pack('N', $i), $password, true); for ($j = 1; $j < $iterations; $j++) { $digest ^= $key = hash_hmac($algo, $key, $password, true); } $hash .= $digest; } // Built-in function returns the length of string, not the length of bytes (not RFC compatible) return substr($raw_output ? $hash : bin2hex($hash), 0, $length); } }