From password_hash() function:
PASSWORD_DEFAULT - Use the bcrypt algorithm (default as of PHP 5.5.0).
Note that this constant is designed to change over time as new and
stronger algorithms are added to PHP. For that reason, the length of
the result from using this identifier can change over time. Therefore,
it is recommended to store the result in a database column that can
expand beyond 60 characters (255 characters would be a good choice).
Does this means whenever PASSWORD_DEFAULT changes i wont be able to use the new php versions because otherwise password_verify() won't be able to correctly check the old user password?
No, password_verify() will recognise the algorithm used, because it's embedded in the hash that you're verifying against: that's what the first part of the hash (e.g. $2y$) indicates
Related
I'm using
password_hash($password, PASSWORD_BCRYPT);
to encrypt passwords to store in a database. As I read, there's no length limit on generated hashes, but I need to know the maximum length so I can use it to define the field in my database which can fit all password hashes (in a worst case scenario).
If I put a limit of 20 characters for the password in plain text, how long will the password_hash() result will be?
From the password_hash documentation:
The following algorithms are currently supported:
PASSWORD_DEFAULT - Use the bcrypt algorithm (default as of PHP 5.5.0).
Note that this constant is designed to change over time as new and
stronger algorithms are added to PHP. For that reason, the length of
the result from using this identifier can change over time. Therefore,
it is recommended to store the result in a database column that can
expand beyond 60 characters (255 characters would be a good choice).
PASSWORD_BCRYPT - Use the CRYPT_BLOWFISH algorithm to create the hash.
This will produce a standard crypt() compatible hash using the "$2y$"
identifier. The result will always be a 60 character string, or FALSE
on failure.
Therefore, using PASSWORD_BCRYPT, the result of password_hash will be a 60 character string.
The result of BCrypt will always be a 60 character string. Limitless is only the input for the function, that means you do not (and should not) set a limit to the entered passwords.
Actually BCrypt internally uses only about 72 characters, but it accepts passwords of any length.
If you want to use the function in its future proof form like this (notice the PASSWORD_DEFAULT)...
password_hash($password, PASSWORD_DEFAULT);
...then you should make your database field bigger. Newer PHP versions may replace BCrypt with another default hash algorithm, which may generate longer hashes.
From the php page: http://php.net/manual/en/function.password-hash.php
PASSWORD_DEFAULT - Use the bcrypt algorithm (default as of PHP 5.5.0). Note that this constant is designed to change over time as new and stronger algorithms are added to PHP. For that reason, the length of the result from using this identifier can change over time. Therefore, it is recommended to store the result in a database column that can expand beyond 60 characters (255 characters would be a good choice).
Would this mean that if I password_verify a password with a later version e.g. PHP8, it might not be able to decipher the stored password correctly? Or is all that information safely embedded already and all I have to do is store the output of password_hash into my DB and just call password_verify for validation without worries?
Would this mean that if I password_verify a password with a later version e.g. PHP8, it might not be able to decipher the stored password correctly?
No. The password hash includes information on which specific algorithm was actually used. If a future version of PHP supports more than one password hashing algorithm, it will be able to read that information from an old hash to figure out how to reproduce it.
(Specifically, the $2y$ prefix currently present on all hashes indicates that they were generated using the PASSWORD_BCRYPT algorithm. Any future algorithm will use a different prefix.)
Yes, all the information is safely embedded, provided that your database doesn't truncate the encrypted password. Which is pretty much a given, I'd think.
What that warning is driving home is that, for your future self's sanity, you store the information in a field whose length is flexible. Historically, like with MD5, one might have chosen CHAR(32). But with bcrypt, you need to choose something more flexible. That might be:
VARCHAR(255)
CHAR(60), with this column being the last one in the table, so that extending its length might not require the RDBMS to reshuffle table.
This question already has an answer here:
password_hash() PASSWORD_DEFAULT PHP 5.5
(1 answer)
Closed 8 years ago.
On PHP's site here: http://php.net/manual/en/password.constants.php, this following is stated:
PASSWORD_DEFAULT (integer)
The default algorithm to use for hashing if no algorithm is provided. This may change in newer PHP releases when newer, stronger hashing algorithms are supported.
It is worth noting that over time this constant can (and likely will) change. Therefore you should be aware that the length of the resulting hash can change. Therefore, if you use PASSWORD_DEFAULT you should store the resulting hash in a way that can store more than 60 characters (255 is the recomended width).
How can this be? If someone sets their password, and the hash is set in the database, and then the method changes, they will not be able to get in, since the method will produce a different hash, will it not?
When you hash a password using the hash_password() function, information about the used algorithm and cost is included in the return string. Therefore, password_verify() can always check whether a provided password is valid given a certain hash.
See the docs for password_hash():
The used algorithm, cost and salt are returned as part of the hash. Therefore, all information that's needed to verify the hash is included in it. This allows the password_verify() function to verify the hash without needing separate storage for the salt or algorithm information.
There's also the function password_needs_rehash() which can be used to check whether a certain hash has been computed with an old algorithm, in which case a new hash has to be computed. Since at the time of a login the password is available as plaintext, you can (and should) at that moment rehash the password if needed.
The warning in the docs about the value changing over time is to make users aware that the length of the computed hash may change. However, the functions are intended to be backwards compatible with older (typically shorter) hashes.
The PHP function crypt() creates a hash for a password. It requires a second parameter for a random salt. This salt can also include additional instructions about which algorithm to use. Seems like a hack, but that's the API. So I add the $6$ prefix to get the SHA-512 hash I need. (Can't use bcrypt for the external non-PHP application that shall also be able to verify the hash. The hash must be verified from PHP and other applications with limited algorithms support.)
Now there are two problems that the PHP manual leaves me alone with:
1) Where do I get a random salt and what requirement does it need to satisfy? I've read about openssl_random_pseudo_bytes and I thought I'd just base64-encode it. But how many source bytes or encoded characters do I need?
2) How can I verify such a hash in PHP again? There doesn't seem to be a single function to do that. I believe I can call crypt again with the same salt as before, but to do that, I need to extract the hash and algorithm and whatever else is needed from the stored password hash. I've seen hashes with variable number of $ characters, so that doesn't seem like a good delimiter to split by.
I've read about phpass but it doesn't support sha-512, so I can't use that.
PHP version is 5.5.9 so some functions may not be available.
Reading the documentation about a new password_hash function for PHP 5.5, I am wondering, what is the default algorithm:
password_hash("rasmuslerdorf", PASSWORD_DEFAULT);
Documentation about it does not clarify this: http://www.php.net/manual/en/password.constants.php
I have had a look into the PHP source code. It defaults to bcrypt in PHP5.5.
From ext/standard/php_password.h line 31:
#define PHP_PASSWORD_DEFAULT PHP_PASSWORD_BCRYPT
This has been updated in the documentation at password_hash() and will be updating shortly in the constants page (I just committed the documentation change about an hour or so ago).
This will be live today at password.constants
From the updated constants page (which hasn't gone live yet, but will be later today):
Available algorithms:
PASSWORD_BCRYPT (integer)
PASSWORD_BCRYPT is used to create new password hashes using the CRYPT_BLOWFISH algorithm.
This will always result in a hash using the "$2y$" crypt format, which is always 60 characters wide.
Supported Options:
salt - to manually provide a salt to use when hashing the password. Note that this will override and prevent a salt from being automatically generated.
If omitted, a random salt will be generated by password_hash() for each password hashed. This is the intended mode of operation.
cost - which denotes the algorithmic cost that should be used. Examples of these values can be found on the crypt() page.
If ommitted, a default value of 10 will be used. This is a good baseline cost, but you may want to consider increasing it depending on your hardware.
PASSWORD_DEFAULT (integer)
The default algorithm to use for hashing if no algorithm is provided. This may change in newer PHP releases when newer, stronger hashing algorithms are supported.
It is worth noting that over time this constant can (and likely will) change. Therefore you should be aware that the length of the resulting hash can change. Therefore, if you use PASSWORD_DEFAULT you should store the resulting hash in a way that can store more than 60 characters (255 is the recomended width).
Values for this constant:
PHP 5.5.0 - PASSWORD_BCRYPT
As far as when and how PASSWORD_DEFAULT will be updated, that's on the password_hash() documentation page:
Note: Updates to supported algorithms by this function (or changes to the default one) must follow the following rules:
Any new algorithm must be in core for at least 1 full release of PHP prior to becoming default. So if, for example, a new algorithm is added in 5.5.5, it would not be eligible for default until 5.7 (since 5.6 would be the first full release). But if a different algorithm was added in 5.6.0, it would also be eligible for default at 5.7.0.
The default should only change on a full release (5.6.0, 6.0.0, etc) and not on a revision release. The only exception to this is in an emergency when a critical security flaw is found in the current default.
The documentation is actually rather specific, if a bit poorly worded; the hash is the strongest one PHP believes it has available at the time, and is subject to change at any time. The hashes produced by password_hash contain a bit of data at the start that indicates which has was initially used to produce them, allowing such upgrades to occur automatically as new hash algorithms become available, without breaking any hashes you have already stored in a database.
Since bcrypt is the only algorithm currently defined, you can probably assume it's the default, but a quick way to verify would be to make a simple PHP script that hashes the same string twice, once with each option, and with a fixed salt, and prints the resulting hashes; they will probably match.
The original password_hash spec may also be of some help. https://wiki.php.net/rfc/password_hash