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.
Related
Consider this line of code by using PHP:
$password = password_hash($password, PASSWORD_DEFAULT);
What will happen if they changed the default password hashing algorithm? I mean I will be having hashed password inside the database. Then, from my own understanding, it will be impossible to check the password because the hashing algorithm will be totally changed.
What would happen is that newly-hashed passwords will be using the new algorithm - obviously.
However, you shouldn't be concerned about this, because the whole thing is designed with forward-compatibility in mind - your code won't be broken when the default algorithm changes, as long as you're using the password_*() functions correctly.
By correctly, I mean use password_verify().
password_verify() accepts a plain-text password and a hash, and it can easily determine what the used algorithm is by looking at the hash that you feed it. Therefore, it would also still be able to verify a password that has been hashed using an old algorithm - not just the previous one, but any algorithm that is supported.
In fact, the sole purpose of the PASSWORD_DEFAULT constant is that you can easily migrate older hashes to a new algorithm (once one is added). This happens the following way:
When a user logs in, you verify their password via password_verify() (any hashing algorithm that has a PASSWORD_<name> constant will work).
You call password_needs_rehash(), and if the password you just verified is using an older algorithm (or a lower 'cost' paramater) - it will return boolean TRUE.
If boolean TRUE was indeed returned, you can now replace the old hash with one that uses the new algorithm; you can do that during a login, because the user just gave you the password and you verified that it is correct.
In summary - it's a really, really well-designed API and it solves problems for you that you haven't even thought about. Don't worry about it.
Edit (noted in the comments):
It should be noted, however, that new algorithms will quite probly result in longer hash lengths, so if you're storing the passwords in a database - don't limit the field's length (i.e. use a varchar(255) field).
Just for clarification, I would like to add to the answer that PHP uses the following structure. Thus, the password_needs_rehash() and password_verify() functions will check the algorithm and cost and do their work to keep everything compatible and correct.
Source: http://php.net/manual/en/faq.passwords.php
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.
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
I'm trying to reverse-engineer a password scheme on a legacy PHP application, so I can port the passwords to a new system which will be replacing it. The application has passwords stored in two formats, a newer and an older one. The newer one simply uses crypt() with salt. The older one doesn't seem to have any supporting code any more (at least not in version control), and no hint of what may have been used. I have one account in the old style for which I may know the password, but I don't know how to check it.
The password is stored in the following format:
$1$f1KtBi.v$nWwBN8CP3igfC3Emo0OB8/
It appears to be three fields, delimited by $: 1, f1KtBi.v, and nWwBN8CP3igfC3Emo0OB8/. The first field is always 1. The second and third fields always match the regular expression [a-zA-Z0-9/.]+. The second field always has 8 characters, the third field always has 22.
Have you seen this password storage scheme before? Any idea what hashing mechanism might have been used?
This is the output of the crypt()[docs] function.
The 1 means that it used the MD5 algo internally.
That's most likely produced with crypt(), especially with MD5:
CRYPT_MD5 - MD5 hashing with a twelve character salt starting with $1$
Good luck finding the salt.
SQLite doesn't have MD5 built in, so I'm considering using the hash function instead. I don't know much about hashing, but I can see that hash() output is numerical and of varying length while MD5() returns mixed characteds/numbers of a fixed length.
I couldn't find anything on this on stackoverflow or google.
Can hash() with salt be used to safely store passwords?
EDIT: Super embarassing mistake, I actually ment hex(), not hash() - Sorry for the error
hex() is not a cryptographic function. All it does is return the hexadecimal value of the string you pass into it. This is not a secure way of storing passwords.
You want to create a hash value before storing the password in your SQLite database. Use the PHP hash() function as other answers have suggested.
You have this tagged as PHP as well, so why not use a PHP function to accomplish what you need? PHPass seems to be hot right now as people are moving away from sha1() and md5().
You can use hash to store passwords as long as you use seed, and use individual seed for every password. The hash function creates value which is unique for a unique string (you can hash other datatypes as well) so it is a good candidate for your task.
With the php hash function you can pass SHA256 to the first parameter and it will create a strong hash of the password + salt. There is no need for extra extensions, for a web application other than a high security system like a banking site, sha256 is fine. It may even be overkill.
hash('sha256',$salt . $password);
Should do the trick. Now you can save the data in a varchar column in your database since the hash function outputs a hex string. The hash function has variable output because it can use many different hashing algorithms. the hash function with sha256 as show above, will output 64 characters in a string. Putting the salt at the beginning is better than putting it at the end, as more randomness at the beginning of hashes is better than randomness at the end.
I couldn't find anything in the SQLite docs regarding a hash() function. You may be using SQLite with some basic third-party C/C++ plugins included, or you may be using the PHP hash() function (which allows you to specify the hashing algorithm to use).
Generally, a one-way hash is a good way to store passwords, and if it's the PHP hash, used with SHA256, I see no reason why it wouldn't work for you. Just be aware that some hashing functions have demonstrated flaws; MD5 can produce predictable and exploitable collisions, and SHA1 also has theoretical vulnerabilities. SHA2 algorithms including SHA256 are based on SHA1, but have not yet been shown to suffer the same weakness.
In any case, to help ensure a unique hash, use a hashing algorithm that produces a hash equal or larger than the message; it is trivial to prove that, given a finite set of hash values, there cannot be a unique hash value for each of the set of messages larger than the hash size.
Chances are you are using the PHP hash() function, which is more then functional. I would stay away from SHA1 and MD5, as they both have vulnerabilities or known reverse-lookup tables (IE, if someone got the hashed password, they could go to many sites available online and enter that in, and it will give them a password that will, when passed through MD5 or SHA1, give the same password.)
hash(256) or hash(512) are way more than what you could probably need, so those will probably be safe. Just remember to salt your passwords. You can never be too careful.