I'm currently working on a "helper function" for PHP's core to make password hashing more secure and easier for the majority of developers. Basically, the goal is to make it so easy, that it's harder to invent your own implementation than to use the core secure one. It's also designed to be updated and extended in the future as hashing methods improve.
I've written an RFC for the addition, and have an implementation of the functions as well.
The basic premise is that crypt
is too difficult to directly use correctly for the majority of developers. The weird error returns, the base64-like (but using a different alphabet) salts, etc. So these functions are designed to take that guesswork out, and provide a dirt simple API.
string password_hash(string $password, string $algo = PASSWORD_DEFAULT, array $options = array())
bool password_verify(string $password, string $hash)
string password_make_salt(int $length, bool $raw_output = false)
Password_Hash takes in a password, an optional algorithm specifier (right now, only the improved CRYPT_BCRYPT
implementation is supported, but would like to add scrypt
as an option later), and a options array. The options array can specify the cost
parameter to bcrypt, as well as a predefined salt value.
Password_Verify accepts a password, and an existing hash. It then re-hashes the password (identical to $tmp = crypt($password, $hash)
). Then, it uses a constant-time comparison function to determine if the two hashes are indeed equal.
Password_Make_Salt exists to generate a random string of the given length. If raw_output
is set to false (default), the outputted "salt" will be base64 encoded in a way that's directly compatible with crypt()
. If raw_output
is true, it will return the same length string using random full-bytes (0-255
).
Example:
$hash = password_hash("foo");
if (password_verify("foo", $hash)) {
// always should be true
} else {
}
A note on reading PHP's source code: PHP functions (those exposed to php code) are surrounded by the PHP_FUNCTION()
macro. Additionally, php variables (zval's) are used in a few places. The macros that access parts of them are
Z_TYPE_P()
(finding the type of a pointer to a zval)Z_STRVAL_P()
(get the pointer to the string value)Z_STRLEN_P()
(get theint
length of the string type)Z_LVAL_P()
(get thelong
value of the integer type)
Additionally, zval_ptr_dtor()
is a refcount mechanism to decrease the refcount on a zval
, and clean it up if it hits 0
.
I'm looking for a review of the implementation by at least a few security experts prior to officially proposing the change. It's reasonably short (only about 300 lines of code)...
Update
The API has been approved, so I've set up a Pull Request for the functionality. Please review it if you have time. Thanks!: https://github.com/php/php-src/pull/191