Create and verify sha-512 password hashes with crypt() and PHP - 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.

Related

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.

PHP mcrypt_get_iv_size () for Salt Size Generation

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.

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.

How to make a permanent tripcode?

I mean, crypt()'s return is always different.
So how do websites like 4chan do to give a permanent tripcode to a password?
Are they stored in a database?
4chan's tripcodes are created using a specific formula, and are a shorter version of a hash. You can achieve the same effect by using MD5 or SHA1.
Encrypt string to MD5 (PHP):
$md5 = md5("$string");
Encrypt string to SHA1 (PHP):
$sha1 = sha1("$string");
There is no way to reverse the hashing process (just like tripcodes), but with time and power they can be "bruteforced" back to plain text.
It's quite common to salt a password, then hash it using DES, MD5, SHA, or newer hashes. The salt is then stored as part of the password.
PHP's crypt works this way, although the exact algorithm it uses to hash the password may be different between versions of PHP... and even between operating systems, although the latter supposedly changed in PHP 5.3. (PHP now includes its own hashing library instead of relying on the OS library, which is really, really important if you're using Windows, as crypt function on Windows only supported DES with 2-byte salt prior to this)
Edit:
Note: crypt has an optional second argument. Passing the encrypted password as the second argument will usually get PHP to detect the salt and algorithm used to originally hash the password, namely because everything other than DES start with $#$ where # is a number.
You pass the salt to crypt() as the second argument. This causes the output to use that salt instead of generating one on the fly.
The salt being randomly generated is why crypt("something") returns different results each time. If I run crypt("something", "ab"), it'll be identical every time. I don't have PHP here to check what the value is, though.
Wikipedia has an article about Tripcodes.
I think there's a table "tripcodes" where tripcodes were generated with the Wikipedia's and they are associated with strings they come from, no?
Yes password are stored in a database but without the use of crypt(). They use sha1() or encryption database function like AES_ENCRYPT() in mysql.

How do I create a unix password hash with php

I'm trying to create system users with a php script securely, In that, I'd like to be able to hash the password with the php script, so that their password shows up nowhere in the bash history.
How to I take a string, and hash it so it is a unix password hash?
$UX_PW = some_function('my_password');
exec("useradd -p $UX_PW newusername");
It's crypt() that implements the UNIX password hashing.
http://us.php.net/manual/en/function.crypt.php
Depending on your system, you're either looking for crypt() or md5().
Traditionally, unix uses DES-encrypted passwords (thats the 'crypt' function), with a 2-character salt (two random characters from the set [a-zA-Z0-9./]) which is prepended to the hash to perturb the algorithm.
Newer systems often use MD5 though.
Use crypt. Recent linux/unixes use CRYPT_MD5 or
CRYPT_BLOWFISH. MD5 is the most widely supported one. DES's are for old systems.
Also I should note that the MD5 version is not a simple MD5 sum operation, it also uses a "salt" value to make hashes not-precalculatable. [[ I made up this term :) ]]
The password-hashing used on UNIX, Linux, and other UNIX-like POSIX operating systems varies a lot. Most "passwd" hashing methods uses a modified DES algorithm (not true DES), they may apply the hashing to the input multiple times, and they use a salt of 16 or 24 bits. A specific answer of the method to produce a passwd-compatible hash depends on which operating system you're using.
The crypt() system call should be the way to do password hashing according to your operating system. You can access it in PHP using the function crypt().
As for which crypt algorithm to use, this depends on your operating system.
From the Ubuntu Intrepid man page on passwd (change password)
The security of a password depends upon the strength of the encryption algorithm and the size of the key space. The UNIX System encryption method is based on the
NBS DES algorithm and is very secure. The size of the key space depends upon the randomness of the password which is selected.
Also, instead of using crypt() you may prefer hash() because this allows you to keep the string setting for the hash algorithm elsewhere. If your code needs to use a different hash algorithm for other environments, you'll only have to change the string and not the name of the function.

Categories