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.
Related
I'm working on storing the password of my users in my database in a secure way. I read a bit and I was recommanded to use openssl_random_pseudo_bytes to generate my salt. I do:
bin2hex(openssl_random_pseudo_bytes($thenumberIwanttouse, $cstrong));
It works, but I was wandering two things:
-What should be the lenght of my salt and in my database, if my salt have 30 character for exemple, I would just need a varchar field with a length of 30?
-Will openssl_random_pseudo_bytes always generate a new salt?If not, should it mean that I need to compare my salt to all other existing salt in my database to make sure that there aren't any duplicate?
The raw format length of the salt is 16 bytes and it is NOT hex-encoded. However, you are not supposed to generate it yourself, nor to have a separate field for salt in the database!
password_hash() will automatically generate a salt (and it will do that better than you could), and then store it in the hash itself - that's just how the algorithm works.
You shouldn't be using anything but password_hash() and password_verify() to make the whole thing work.
In addition, there are better alternatives to openssl_random_pseudo_bytes() for generating random data, such as random_bytes() under PHP7, or it's backport for older PHP versions - the random_compat package.
I am trying to use SHA512 algorithm in PHP using function crypt.
My salt:
$salt = base64_encode(substr(str_shuffle("./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"), 0, 12));
I get something like this:
Q4CALzJNenFaZnNK
I am not sure why I get lenght 16 while I specified 12.
And to hash the password, I use this:
$hashed = crypt('myPassword', '$6$rounds=5000000$'.$salt);
The output is something like that:
$6$rounds=5000000$Q4CALzJNenFaZnNK$9QTP6C.BZ9Z.U85UIEAVX1dEIdShHFoYGgTMvgv9Cx/XZY1mK/n2rY4FuHSoigjgIXfqGZftZSxrrF.cDBzt8/
Lenght: 121
So my question is it ok to store this password in the database or should I strip $ signs as I saw in few examples?
Also I already store passwords in VARCHAR(255) and I was wondering if I could make the output twice as long, i.e. near 255 characters?
Is this way more secure than for instance Blowfish?
My findings:
The length of a hashed password is not that important as I first thought (60 characters is well enough to store instead of 128 or 256).
It is best to use password_hash function and forget about generating your own salt - php.net know what they do.
So I ended up hashing passwords this way:
$hash = password_hash($password, PASSWORD_BCRYPT, array("cost"=>15));
PASSWORD_BCRYPT is Blowfish algorith with the default cost of 10 (times it runs the algorithm or something). 10 is a good number to slow down the brute force attacks. I wanted to show how you can change the cost manually.
You get a larger salt back because of base64_encode will enlarge your 12 character string to a 16 character string (it's encoding does that)
You can store the string fully in one field but if you want easy access to the salt, you could store the salt in another field. (You need the salt again to recheck if the user password input is correct - the salt only makes sure that a hash of the same password wouldn't give the same hash)
Is SHA512 safer as Blowfish? As erickson on stackoverflow said, they are both good enough for the purpose
You have this:
$salt = base64_encode(substr(str_shuffle("./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"), 0, 12));
You can simply remove the base64_encode from this to get a 12 character salt. Also note that in your version you have some non-ascii, non-printable characters between the 5 and the 6. That probably causes the binary output. Try this:
$salt = substr(str_shuffle("./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"), 0, 12);
So my question is it ok to store this password in the database
Yes, just store the whole thing in the database, including the $6$ and the rounds=5000000. This makes it possible to switch to another hash type in the future, and you can just use crypt on the whole password to check it.
Also I already store passwords in VARCHAR(255) and I was wondering if I could make the output twice as long, i.e. near 255 characters?
In principle longer is better, so SHA512 is better than SHA256. However, a 120 character hash is already pretty long and there is no advantage to make it even longer. You can increase the length of the salt, but don't try to make the hash longer by appending another hash or something like that.
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
I am using Crypt() in PHP to encrypt passwords.
Let's say salt is "bg",
Password is: "gg456456gg"
Encrypted result gives: "bgvQk9C2Pv27o"
But if I use password: "gg456456" - without two last characters, it gives same result.
Because of this, users are able to login without typing 100% exact password.
What's happening? I mean gg456456 and gg456456gg are two different passwords, why is encrypted result same?
Php.net on function crypt()
The standard DES-based crypt() returns the salt as the first two
characters of the output. It also only uses the first eight characters
of str, so longer strings that start with the same eight characters
will generate the same result (when the same salt is used).
So use a different encryption method.
Such as blowfish or sha-512. These will accept much longer strings
E.g. SHA-512:
$encpassword = crypt($password,"$6$".$salt);
Used the method above (and same salt):
gg456456 -> $6$631080661$L2o7HNKfYrqB4H19vYe7fRWWLenQj2EcWqriNG9rX6ki1QKO2YytkylrYmZ8mhIr6XE19Ms4RW2of5Z/dsYRA/
gg456456gg -> $6$631080661$maGxQ2d7ZIPIdXDFN1sJJsIjTFEwD9dL/uljSXdKXeJU4E5miCzh1ZCao57sGDm9PrDhdPYPLGUvoy0HzTfqI.
Use a good random-number generator for your salt and voila you have a well encrypted password
The original crypt function on Unix systems only uses the first 8 characters of the password. Eventually we decided that was insecure and have switched to more secure password hashes.
The PHP crypt function selects the algorithm to use based on the salt you supply, and a two character alphanumeric salt like you used triggers that original crypt algorithm.
See http://php.net/manual/en/function.crypt.php for the list of algorithms and respective salts.
I have been doing some research on creating some different hashes, etc. I am aware of the password_hash() function, however I'm currently creating an initialization value using mcrypt. The issue that is arising is some of the hashed password being clipped if the password is larger than 8 characters.
My current code adds a salt (created by mcrypt_create_iv()) to a users password. Afterwards it is encrypted using the hash() function. The criteria for a password is anywhere from 8->40 characters.
My column in MySQL looks like varchar (64) using latin1_swedish_ci collation.
How would I calculate the maximum length (MySQL length) that the initialization value could be, as well as the maximum length for the user-inputted password?
Disclaimer: I purposefully left out the encryptions, but will appreciate any documentation for different cipher block init value lengths as well as hash lengths. (Not sure the terminology, hope that makes sense.)
Hash functions as well as password_hash() - which implements different Password Based Key Derivation Functions (PBKDF) using either a HMAC or a ciphered MAC - always return the same amount of data for any input value. If the password is being truncated then that is because of code that happens before any of these functions is called. Normally these functions return 20 bytes if you use SHA-1.
Of course the salt value needs to be stored as well.
If you store that using hexadecimals then you need twice the number of characters compared to the binary value. If you utilize base 64 encoding you need ( (size + 2) / 3 * 4 ) characters if you include padding.
So your password can be as long or short as wanted, the salt takes one byte (encoding) per byte.
It is strongly recommended that you also store some kind of indicator of the function used. That may be a single byte indicating your current protocol. That way you can upgrade your password protocol per entry once a user returns to fill out his (new) password.