Switching from md5() to crypt() - php

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.

Related

password_verify and password_hash in php

I know that password_verify can be used to check a password's validity against a pre-stored hash. I'm also aware that password_hash requires us to choose a hashing algorithm such as PASSWORD_ACTUAL or PASSWORD_BCRYPT.
When password_verify($pass, $hash) converts $pass into hash how will it know which algorithm to use?
It can tell because the hash itself has the required information.
Per PHP documentation:
Note that password_hash() returns the algorithm, cost and salt as part of the returned hash. Therefore, all information that's needed to verify the hash is included in it. This allows the verify function to verify the hash without needing separate storage for the salt or algorithm information.
Reference
For example, a PASSWORD_BCRYPT hash would look like this:
$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
|-----|----------------------|------------------------------|
A1,A2 B C
A1: 2a indicates the hash algorithm. For Bcrypt it's either 2a, 2b, or 2y
A2: 10 is the cost parameter of the hash. This makes the hash safe against timing attacks, since you can just increase this number to increase the "work" it's needed to compute
B: this is the 128-bit salt
C: the resulting 184-bit hash
With all those parameters (for now, just looking at a1) it can already tell what algorithm it is.
Hashes created using PASSWORD_BCRYPT have an identifier at the beginning: $2y$ and also makes sure the length of the hash is 60 characters. password_verify() most likely looks at one or both of these to determine what kind of hash to use.

Precision loss in PHP's Crypt()? Same salt, different passwords = same encrypted result

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.

Is there a hashing method which is 'dehashable'?

I know that hashing functions such as SHA1 and MD5 are one-way encryption systems.
But is there a hashing method which is 'dehashable'?
Like, it produces an x-character string, which can then be 'dehashed' into the original string.
Is there such a hashing method? It will be appreciated if it was PHP compatible.
UPDATE: What I mean by a hashing function is an encryption method which produces an x-character string, which can be decrypted. Sorry for the confusion.
hashing functions such as SHA1 and MD5 are one-way encryption systems.
Not quite - they are as you say hashing functions. They are often used together with encryption systems, e.g. for password hashing algorithms, but they are not encryption systems or encryption algorithms.
But is there a hashing method which is 'dehashable'?
No, it would not be a hash function then, since a hash function maps a larger data set to a smaller data set. This has the side effect that you can get the same hash value out of different input data, which makes calculating the original data from the hash key impossible. What it does allow is, for instance, to check if the original data has been modified - you apply the same hash function to the original data again and compare the calculated hash keys. If they are different, the original data was modified - if they are the same, the original data is (at least very very likely) unmodified.
What you are looking for is probably either a compression/decompression algorithm or an encryption/decryption algorithm.
Hashing is not (one-way) encryption, as a hash value can never be decrypted to the original value; this is by design.
Also, hash functions are designed to make it very hard to come up with a data set the will match a given hash value (cf. collision)
As Andreas suggests, you are looking for compression or crypto functions.

How secure is encryption for passwords with crypt() in PHP?

I'm using crypt() encryption in PHP like this:
<?php
$password = sanitizing_func($_POST['password']);
$var = crypt($password, 'ab');
?>
How Secure is this?
Found a better solution here: openwall phpass
Thanks to Edward Thomson
It's less secure than if you just use crypt the way it was designed, with the password as the first argument and the salt as the second.
Now you're encrypting known plaintext using the user's password as the salt. If your system uses an MD5 crypt, then you've just limited the salt space to 12 characters, so you're truncating the space of users passwords to twelve characters. Worse still, my system requires me to use a prefix on the salt in order to specify my crypt, or else I get old school crypt, meaning you have two characters for the salt. So you've limited the possible length of a users password to two characters. Plus there's no point in even running crypt at this point, you might as well just store their two character password, since the salt is prefixed to the ciphertext so that subsequent calls to crypt can pass the same salt.
Also, you're limiting the character space of the password by using it in the salt, since the character space of the salt is limited to A-Z, a-z, 0-9, ".", "/". Even if you switch the arguments around from your code example, you're using the same salt data for every call. This means that every password has the same salt. So if your password table is exposed, it becomes less computationally expensive to crack using a dictionary attack.
In other words, swapping the password and salt arguments is a fatal mistake.
Finally, there's simply no reason to call crypt twice. If you want better encryption, use a better algorithm, don't call it more frequently. For example, if you're using a DES crypt, then it's still an ancient algorithm no matter how many times you call it. (I also seem to remember reading that multiple passes of an algorithm may inadvertently produce weakened ciphertext. But I don't have Schneier in front of me.)
What you want to do is the industry standard: use a strong crypt, pass the password as the first argument and random salt data in as the second argument and make sure that you're passing the maximum allowable number of bytes in for the salt.

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