diff options
author | Anthony Ferrara <ircmaxell@gmail.com> | 2012-06-25 10:52:14 -0400 |
---|---|---|
committer | Anthony Ferrara <ircmaxell@gmail.com> | 2012-06-25 10:52:14 -0400 |
commit | aca60d08ac0ca5a9045ecb817637ed7f21e058c4 (patch) | |
tree | 497383431640800b7e6511242b8485be013d8f12 | |
parent | 7a9d901cd13dc2cb8d9751a898197bacb81f5d0d (diff) | |
download | password_compat-aca60d08ac0ca5a9045ecb817637ed7f21e058c4.zip password_compat-aca60d08ac0ca5a9045ecb817637ed7f21e058c4.tar.gz password_compat-aca60d08ac0ca5a9045ecb817637ed7f21e058c4.tar.bz2 |
Add compatibility layer for pre-5.5 functionality
-rw-r--r-- | lib/password.php | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/lib/password.php b/lib/password.php new file mode 100644 index 0000000..74ce83b --- /dev/null +++ b/lib/password.php @@ -0,0 +1,150 @@ +<?php + +defined('PASSWORD_BCRYPT') or define('PASSWORD_BCRYPT', '2y'); +defined('PASSWORD_MD5') or define('PASSWORD_MD5', '1'); +defined('PASSWORD_SHA256') or define('PASSWORD_SHA256', '5'); +defined('PASSWORD_SHA512') or define('PASSWORD_SHA512', '6'); + +defined('PASSWORD_DEFAULT') or define('PASSWORD_DEFAULT', PASSWORD_BCRYPT); + +define('PASSWORD_BCRYPT_DEFAULT_COST', 11); +define('PASSWORD_SHA_DEFAULT_ROUNDS', 5000); + +if (!function_exists('password_create')) { + function password_create($password, $algo = PASSWORD_DEFAULT, $options = array()) { + if (!function_exists('crypt')) { + trigger_error("Crypt must be loaded for password_create to function", E_USER_WARNING); + return false; + } + if (!is_string($password)) { + trigger_error("Password must be a string", E_USER_WARNING); + return false; + } + if (!$algo) { + $algo = PASSWORD_DEFAULT; + } + switch ($algo) { + case PASSWORD_BCRYPT: + $cost = PASSWORD_BCRYPT_DEFAULT_COST; + if (isset($options['cost'])) { + $cost = $options['cost']; + if ($cost < 4 || $cost > 31) { + trigger_error(sprintf("Invalid bcrypt cost parameter specified: %d", $cost), E_USER_WARNING); + return false; + } + } + $required_salt_len = 22; + $hash_format = sprintf("$2y$%02d$", $cost); + break; + case PASSWORD_MD5: + $hash_format = "$1$"; + $required_salt_len = 12; + break; + case PASSWORD_SHA256: + case PASSWORD_SHA512: + $rounds = PASSWORD_SHA_DEFAULT_ROUNDS; + if (isset($options['rounds'])) { + $rounds = $options['rounds']; + if ($rounds < 1000 || $rounds > 999999999) { + trigger_error(sprintf("Invalid SHA rounds parameter specified: %d", $rounds), E_USER_WARNING); + return false; + } + } + $required_salt_len = 16; + $hash_format = sprintf("$%s$rounds=%d$", $algo, $rounds); + break; + default: + trigger_error(sprintf("Unknown password hashing algorithm: %s", $algo), E_USER_WARNING); + return false; + } + if (isset($options['salt'])) { + if (is_string($options['salt'])) { + $salt = $options['salt']; + } else { + trigger_error('Non-string salt parameter supplied', E_USER_WARNING); + return false; + } + if (strlen($salt) < $required_salt_len) { + trigger_error(sprintf("Provided salt is too short: %d expecting %d", strlen($salt), $required_salt_len), E_USER_WARNING); + return false; + } elseif (0 == preg_match('#^[a-zA-Z0-9./]+$#', $salt)) { + $salt = str_replace('+', '.', base64_encode($salt)); + } + } else { + $salt = password_make_salt($required_salt_len); + } + $salt = substr($salt, 0, $required_salt_len); + + $hash = $hash_format . $salt; + + $ret = crypt($password, $hash); + + if (!is_string($ret) || strlen($ret) < 13) { + return false; + } + + return $ret; + } +} + + + +if (!function_exists('password_verify')) { + function password_verify($password, $hash) { + if (!function_exists('crypt')) { + trigger_error("Crypt must be loaded for password_create to function", E_USER_WARNING); + return false; + } + $ret = crypt($password, $hash); + if (!is_string($ret) || strlen($ret) != strlen($hash)) { + return false; + } + + $status = 0; + for ($i = 0; $i < strlen($ret); $i++) { + $status |= (ord($ret[$i]) ^ ord($hash[$i])); + } + + return $status === 0; + } +} + +if (!function_exists('password_make_salt')) { + function password_make_salt($length, $raw_output = false) { + if ($length <= 0) { + trigger_error(sprintf("Length cannot be less than or equal zero: %d", $length), E_USER_WARNING); + return false; + } + + if ($raw) { + $raw_length = $length; + } else { + $raw_length = (int) ($length * 3 / 4 + 1); + } + + $buffer_valid = false; + + if (function_exists('mcrypt_create_iv')) { + $buffer = mcrypt_create_iv($raw_length, MCRYPT_DEV_URANDOM); + if ($buffer) { + $buffer_valid = true; + } + } + if (!$buffer_valid && function_exists('openssl_random_pseudo_bytes')) { + $buffer = openssl_random_pseudo_bytes($raw_length); + if ($buffer) { + $buffer_valid = true; + } + } + if (!$buffer_valid) { + for ($i = 0; $i < $raw_length; $i++) { + $buffer .= chr(mt_rand(0, 255)); + } + } + + if (!$raw) { + $buffer = str_replace('+', '.', base64_encode($buffer)); + } + return substr($buffer, 0, $length); + } +}
\ No newline at end of file |