PHP mcrypt_get_iv_size () for Salt Size Generation - php

I am writing a PHP script to authenticate users. I want to use SHA512 for the hash and use a salt to prepend to the password. To generate the salt, I want to use mcrypt_create_iv. But first, I must figure out the initialization Vector size. For this, I see php has: mcrypt_get_iv_size. But I have a question, please:
For mcrypt_get_iv_size() what do I use for the cipher string and the mode string? Please keep in mind I am using SHA512, so the salt needs to be at LEAST as long as the sha512 hash. For experimenting, I tried " mcrypt_get_iv_size(CRYPT_SHA512, MCRYPT_MODE_CFB) " but php complained.

Actually mcrypt_create_iv() was designed to generate a random binary string, which can be used for encryption. What you want to do is hashing not encryption, so mcrypt_get_iv_size() does not make sense here.
Since PHP 5.3 it is safe to use mcrypt_create_iv() to generate a random string, but keep in mind that you get a binary output, which does not fit into the alphabet of the hash function.
You can look at this example which shows how to use mcrypt_create_iv() for generating a salt. To hash a password you should not use sha512 though, instead use a key derivation function like BCrypt, which is slow.

The length of the salt has nothing to do with the IV size of any cipher. Rather you need to figure out how many bytes of random data are needed for your particular hashing algorithm, taking the salt formatting into account. For examples bcrypt needs 16 bytes with base64-esque encoding.
Anyway, the mere fact that you need to ask this question means that you don't know what you're doing and that's a really bad sign when it comes to password hashing. Please use one of the existing libraries for this purpose instead.

Related

Create and verify sha-512 password hashes with crypt() and PHP

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.

Need to hash up to 500 char string (think password style encryption), that would be difficult to reverse

I am storing "secret" strings in a database as a hash (in case data is compromised). I was using bcrypt, but found out that it apparently only takes the first 55 characters. Basically someone will try to guess these secret strings, and I currently hash their guess and compare it to the hashed "secret" string.
What would be the best way to do this? Bcrypt will not work since some strings will be up to 500 characters. Any Ideas?
Don't just use a plain hash(be it MD5, SHA-1 or SHA-2) if inputs are guessable. Validating a guess is cheap with them.
A simple trick is to first hash the input with SHA-256 (cutting it down to 32 bytes or 43 Base64 chars) and then apply bcrypt to that.
That way bcrypt takes care of being expensive and salted, and SHA-256 takes care of large inputs.
See https://security.stackexchange.com/questions/30315/fixing-the-high-bit-problem-in-phps-crypt-implementation/30326#30326
You can try using Blowfish - symmetric encryption algorithm without length limitations.
PHP Pear has implementation for Crypt_Blowfish class.
If ability to decrypt is not necessary, it would be better to use something like SHA1. PHP also has support for it.
I'm a huge fan of MD5, it's faster than SHA and it's virtually un-reversible. I have used it to do entire files as a checksum comparison. Besides it's a built in function in PHP.
Simply MD5 the incoming string and compair it to the MD5ed answer stored in the database.
The MD5 string is only 32 characters long. While it his wonderful for keeping database size down, there is a possibility that two long string will actually have the same MD5 result, but this is highly improbable.

Switching from md5() to crypt()

So far I have been using md5 to hash passwords on my site, no salt.
Now I am building an application that will have to be more secure and I'm reading md5 can be easily brute-force attacked.
So I want to use crypt() to hash the passwords.
What I have not fully understood is:
Do I have to provide a salt or is the built-in generated one ok?
How many times (if more than one) should I iterate the crypt function to be safe?
With md5, no matter the length of the input string, the hash was 32-digit. Does crypt return a standard length of hashes too?
You need to provide a salt, if you want to specify encryption other than DES. Otherwise, you're good with the default salt.
You don't iterate the crypt function yourself, this is done internally with algorithms where it makes sense. Number of iterations is specified via the salt.
Yes, the hash length of a given hash algorithm is standard; different hash algorithms have different hash lengths, however.
crypt can use different hash algorytms. With md5 it returns 128 bit integer (with 32 chars hex representation). Using crypt with a salt once is safe enought. It's recommended the salt to be provided by the application
An optional salt string to base the hashing on. If not provided, the
behaviour is defined by the algorithm implementation and can lead to
unexpected results.

Generating user unique hmac keys for password hashing

For my website's password hashing I wrote the following function:
public function hash($user) {
$user_key = hash_hmac('sha512', $user['id'].$user['email'], $this->site_key);
$password = hash_hmac('sha512', $user['password'], $user_key);
}
I generate user unique keys to use for the final password hashing. Because this key is hashed with sha512 it should give enough security based on what I read on wikipedia:
The cryptographic strength of the HMAC depends upon the cryptographic strength of the underlying hash function, the size of its hash output length in bits and on the size and quality of the cryptographic key.
I have not seen this way if hashing passwords before and was wondering if it is good enough?
Extra: I have not used a salt because I think hmac appends the provided key to the data (like a salt), is this right?
OK, first and foremost. Do not write up your own function to do password hashing. I'm not doubting your skills, but to be safe do not do your own hashing system. And an HMAC your key is OK, but I'd still not use it.
Finally I'd suggest that you do this for your users passwords.
<?PHP
$password=$user['password'];
$username=$user['username'];
$salt='usesomesillystringforsalt';
$hashed_password=crypt($password.$username,'$2a$04$usesomesillstringforsalt$');
?>
This algorithm uses Bcrypt which is based upon Blowfish it is a very robust algorithm and is what Gawker media went to after they were hacked due to the robustness and usefulness for password hashing. crypt PHP Manual
Next up, remember to change the part that says usesomesillystringforsalt to something else. It needs to be 22 digits of base64 salt A-Z,a-z,0-9,/ and "."
Go to that link to find out more about the algorithm itself. I suggest that you just use this implementation as it is much much stronger than the one that you were suggesting.
If you want to go a step forward, I'd suggest that you use a unique salt for every user. If you want to do that, I can write up an example function which will show you how to do that.
As stated, if you have any more questions feel free to ask.

SQL: MD5() vs hex()

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.

Categories