Decrypting password after a password hash encrypt - php

This is my password encrypting code :
// Create a 256 bit (64 characters) long random salt
// Let's add 'something random' and the username
// to the salt as well for added security
$salt = hash('sha256', uniqid(mt_rand(), true) . 'something random' . strtolower($username));
// Prefix the password with the salt
$hash = $salt . $password;
// Hash the salted password a bunch of times
for ( $i = 0; $i < 100000; $i ++ )
{
$hash = hash('sha256', $hash);
}
// Prefix the hash with the salt so we can find it back later
$hash = $salt . $hash;
I lost the tutorial site. Do anyone know how to decrypt this encryption. Thank you very much. Appreciate your help

There is no *de*cryption algorithm because there's no *en*cryption algorithm. What you're doing is a hash, which is a non-reversible operation. And that's exactly the point, you do not want to store anything that would even allow you the chance of knowing what the actual secret password is.

A hashing function is not the same thing as encryption. Check the Wiki on hashing. Bottom line is: a hash is a one way algorithm. You can't decrypt it in one go. You could brute-force it, but (especially with sha256) that would take ages. If you were to have a machine, dedicated to cracking a sha256 hash, it'd take ~= 10^64 years!. If 10^64 is meaningless, here's the number in full:
100.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000
And even then, there's no guarantee the result will be right: you could end up with a hash collision (google it). If you do: cheer up, you'd be the first, AFAIK.
For more on encryption vs hashing, refer to this answer to a previous SO question
So the answer is: You can't decrypt (or rather de-hash) what you have.

Related

Providing a salt for encryption with 'crypt()' isn't affecting the output + questions on crypt

I have this code in a PHP page which I am running multiple times. Every time I refresh the page, the salt changes (as it should), but the hash output stays the same.
$iv = mcrypt_create_iv(22);
$ro = rand(6, 9);
$salt = '$2y$'.$ro.'$'.$iv.'$';
echo $salt;
echo '<br />';
$crypt = crypt('test', $salt);
echo $crypt;
Shouldn't the random salt affect the output and make it so that every time I refresh the page the crypt result changes too?
I also have a few general questions on crypt().
Is there any way for you to use a specific hashing algorithm with this function? I would like to use the blowfish algorithm.
Is it the salt length/format that affects which algorithm it chooses?
Lastly, should the salt length for the blowfish algorithm always be 22 characters, or is that just the maximum?
By the way, if anyone is wondering (and if it matters for answering these questions and wasn't obvious), I'm planning to use something similar to store hashed passwords.
Thank you for looking!
The crypt() function on your system does not support the "2y" algorithm. At least Linux GLIBC 2.7 based systems only know DES, $2a$ (blowfish), $5$ (SHA-256) and $6$ (SHA-512). Therefore, the crypt() function assumed DES and only took the first two characters "$2" as salt. That of course produced always the same output.
Try SHA-512 for secure password hashes:
$salt_chars = array_merge(range('A','Z'), range('a','z'), range(0,9));
$salt = '$6$';
for($i=0; $i < 8; $i++) { $salt .= $salt_chars[array_rand($salt_chars)]; }
echo "salt=$salt\n";
$crypt = crypt('test', $salt);
echo "crypt=$crypt\n";
Regarding your second question, you can chose the algorithm by starting the salt with e.g. "$2a$" (instead the $6$ above) for blowfish. Read "man 2 crypt" for details. For some algorithms you can also encode more parameters like "rounds=4000" into the salt.
According the the crypt() manpage, the salt may be up to 16 characters following the $id$.
Longer salts will silently be truncated and produce the same output as for only the first 16 characters.
BTW, even in /etc/shadow, passwords only use 8 characters of salt with the SHA-512 algorithm. As the salt is only to make rainbow table attacks harder, this seems sufficient.

Does a salt and pepper password count as 96-bit encryption?

I have created this code for a salt and pepper password encryption. I assume this is a good way to encrypt passwords, but what level of encryption is this?
I first thought the 'bit' part was the length of characters used but I know that is incorrect. How many bits of encryption would this be?
PHP
function _h() {
$result = "";
$charPool = '0123456789abcdefghijklmnopqrstuvwxyz';
for($p = 0; $p<32; $p++)
$result .= $charPool[mt_rand(0,strlen($charPool)-1)];
return md5(sha1(md5(sha1($result))));
}
$salt = _h();
$pepper = _h();
$pass = $salt.md5($salt.md5($_POST['password']).$pepper).$pepper;
UPDATE
I understand this is not encryption, so I would not be able to say this is encrypted, but instead hashed. Is a hashed password with a salt and pepper secure enough to save a password?
There are quite a lot of problems with your scheme to hash a password.
PHP 5.5 will have it's own functions password_hash() and password_verify() ready, to simplify generating BCrypt password hashes. I strongly recommend to use this excellent api, or it's compatibility pack for earlier PHP versions. The usage is very straightforward:
// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);
// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);
These functions will solve following problems:
They use a slow adaptable hash function (BCrypt), MD5 is ways too fast for hashing passwords.
They generate a safe salt from the random source of the operating system.
A pepper is not just a second salt, in contrast to a salt, the pepper is secret and will not be stored together with the hash. The same pepper will normally be used for all passwords.
There is no use in complicating the computation of salt and $peppr too much. After all the task is not the retrieval of what was originally used to produce these spices but trather the value of $_POST('a'] and you give away the $saltand $pepper as prefix/suffix (otherwise you couldn't use the stored valuelater to verify an input password with this hash). That being said, do as #zneak commented and use an expert library function.

Login System Hash Salt

I am rewriting a PHP Login system and I just faced this
function createSalt()
{
$string = md5(uniqid(rand(), true));
return substr($string, 0, 3);
}
$salt = createSalt();
$hash = hash('sha256', $salt . $hash);
Actualy I never worked with salting before, I searched a bit and found it useful.
But my answer is, Is this a good way to work with salt?
Wouldn't $string = sha1(uniqid(mt_rand(), true)) be better?
And what about returning only 3 characters of the hash? I really don't get it.
What you think?
Consider using PHP's crypt() instead of reinventing the wheel. It is specifically designed for password hashing, and offers hash algorithms suited for that purpose.
I prefer sha1 or sha256, md5 is super-outdated, the sha-functions are way better. But this is my opinion, choose what you want.
What is really important in this case is the salt. A salt is always stored in plaintext together with the hash and is used to improve the length of a password (if you want to hash the password, might be something else of course) to prevent attacks based on rainbow/lookup tables. This is no protection against cracking the password by using bruteforce (which works quite well against md5, so use sha256 which is harder to crack).
Therefore it is totally unimportant if you use 32 random chars for the hash, or something like md5(mt_rand()) - important is the length. I would use something like
$hash = md5(mt_rand()) . md5(mt_rand());
md5() results in 32 bytes string, based on a random number (mt_rand() is better then uniqueid()). With this simpel line you get a very "strong" hash which should secure every password against rainbow tables.
I don't agree with the given function createSalt() - mainly for the same reasons as you.
My approach to this would be
define(SALT_LENGTH,32);
function createSalt()
{
$string='';
for ($i=0;$i<SALT_LENGTH;$i++) $string.=chr(rand(0,255));
return $string;
}
A good salt is a random byte sequence - no MD5 or SHA1 makes any sense, as there is nothing to hash!
I no master PHP programmer but I've been working on the same hash script for a login system.
Im storing it on GitHub - https://github.com/revitalagency/PHP5-Salt-Super-Admin
I created my hash using...
hash_hmac('sha256', $_POST['pass'], GLOBAL_SALT);
GLOBAL_SALT is defined in a config file not in the DB for extra protection.

Am I using PHP's crypt() function correctly?

I've been using PHP's crypt() as a way to store and verify passwords in my database. I use hashing for other things, but crypt() for passwords. The documentation isn't that good and there seems to be a lot of debate. I'm using blowfish and two salts to crypt a password and store it in the database. Before I would store the salt and the encrypted password, (like a salted hash) but realized its redundant because the salt is part of the encrypted password string.
I'm a little confused on how rainbow table attacks would work on crypt(), anyway does this look correct from a security standpoint. I use a second salt to append to the password to increase the entropy of short passwords, probably overkill but why not?
function crypt_password($password) {
if ($password) {
//find the longest valid salt allowed by server
$max_salt = CRYPT_SALT_LENGTH;
//blowfish hashing with a salt as follows: "$2a$", a two digit cost parameter, "$", and 22 base 64
$blowfish = '$2a$10$';
//get the longest salt, could set to 22 crypt ignores extra data
$salt = get_salt ( $max_salt );
//get a second salt to strengthen password
$salt2 = get_salt ( 30 ); //set to whatever
//append salt2 data to the password, and crypt using salt, results in a 60 char output
$crypt_pass = crypt ( $password . $salt2, $blowfish . $salt );
//insert crypt pass along with salt2 into database.
$sql = "insert into database....";
return true;
}
}
function get_salt($length) {
$options = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./';
$salt = '';
for($i = 0; $i <= $length; $i ++) {
$options = str_shuffle ( $options );
$salt .= $options [rand ( 0, 63 )];
}
return $salt;
}
function verify_password($input_password)
{
if($input_password)
{
//get stored crypt pass,and salt2 from the database
$stored_password = 'somethingfromdatabase';
$stored_salt2 = 'somethingelsefromdatabase';
//compare the crypt of input+stored_salt2 to the stored crypt password
if (crypt($input_password . $stored_salt2, $stored_password) == $stored_password) {
//authenticated
return true;
}
else return false;
}
else return false;
}
You really should have a look at PHPASS: http://www.openwall.com/phpass/ It's a password hashing framework using crypt() which is used in projects like Wordpress and phpBB.
There is also an excellent article on this website about password hashing, salting and stretching using crypt(): http://www.openwall.com/articles/PHP-Users-Passwords
UPDATE:
Currently there's an alternative for the PHPASS library. In the next version of PHP there are special functions for hashing and verifying passwords (using bcrypt): http://www.php.net/manual/en/ref.password.php. There is a compatibility library that implements these functions for PHP 5.3.7+: https://github.com/ircmaxell/password_compat
Your use of crypt() is fine. crypt($input, $stored) == $stored is the way it is designed to be used.
Your get_salt() function is not great, since it is using the often-poor rand() function. You should consider using a stronger random function, like openssl_random_pseudo_bytes(), instead.
The idea of a rainbow table is that an attacker can make a table with all possible passwords and their hashes at home.
E.g.
PASSWORD HASH
iloveSO gjroewjgo
password knbnogjwm
secret gjroehghe
jbieber rewgroewj
etc.
With this table, the attacker can quickly convert any hash to a password. Rainbow table uses some tricks so that not all hashes have to be stored, but it still computes all hashes beforehand.
By using a salt, even when storing it with the password, you make this much harder. Instead of hashing every word in a dictionary, the attacker would now have to hash every word with every salt. With a long enough salt, this gives enough combinations to make it unfeasible to compute all these hashes.
So a salt is not meant to be an extra password, known only to the application, it is meant to change the hash function so that it is non-standard.
This is a misuse of crypt() because you are using a deprecated primitive. Blowfish is very old, twofish is the replacement and even that is old because threefish is almost finalized. You should be using a member of the sha2 family, sha256 or sha512 are both good choices. crypt() can be used with sha256 or sha512, you should use the CRYPT_SHA256 CRYPT_SHA512 parameters respectively.
Also your salts have a very small entropy/size ratio, you are only using an alphanumeric set which is a joke because alphanumeric rainbow tables are the most common. You should be using a full byte which base256, and I recommend a salt that is 256 bytes long. Keep in mind all hash functions are binary safe by definition thus you shouldn't have to worry about null bytes and the like.
Use SHA-512 (if available) with a salt which includes time() and openssl_random_pseudo_bytes(). Crypt is consolidated / efficient because it returns the salt inserted with the hashed string.

What is better hashed or encrypted passwords?

What is best for storing passwords? Should I be Encrypting or hashing password for you users table ?
What do you prefer, and why? Could you please provide an example of secure password storage.
Considering passwords generally don't have to be checked / hashed / whatever that often (they are when one is logging in, and registrering ; but that's pretty much it), speed is generaly not much of a concern : what matters is security.
What's generally done is :
when a user registers, he types his (new) password)
that password is salted + hashed, and the result is stored in database
Then, when a user wants to log-in, he types his password
What is typed is salted + hashed, and compared to the value stored in the database.
The main key is : never store the real password in the DB -- only a hash of it ; and salt it before hand, to avoid attacks by rainbow-tables.
And it seems this is already what you're doing -- so good point for you ;-)
Which hashing function should be used ? Well, sha1 is often considered as OK ; md5 is less OK now ; sha512 should be more than OK, I guess.
I'd do this usually:
<?php
function createHash($pwd, $salt = ''){
$hash = '';
if(!$salt){
$salt = hash('sha256',mt_rand().time().$pwd.'2130A');
}
if($pwd[0] & 0){
if($pwd[strlen($pwd)-1] & 1){
$hash = hash('sha256', $pwd.$salt).$salt;
}else{
$hash = $salt.hash('sha256', $pwd.$salt);
}
}else{
if($pwd[strlen($pwd)-1] & 1){
$hash = $salt.hash('sha256',$salt.$pwd);
}else{
$hash = hash('sha256', $salt.$pwd).$salt;
}
}
return $hash;
}
function getSalt($pwdHash){
if($pwd[0] & 0){
if($pwd[strlen($pwd)-1] & 1){
$salt = substr($pwdHash,64);
}else{
$salt = substr($pwdHash,0,64);
}
}else{
if($pwd[strlen($pwd)-1] & 1){
$salt = substr($pwdHash,0,64);
}else{
$salt = substr($pwdHash,64);
}
}
return $salt;
}
var_dump(createHash('testPassword',getSalt($pwdHashFromDb)) == $pwdHashFromDb); // true
Salting provides higher security than a usual hash.
The salt position depends on the entered password, and thus this makes the salt less vulnerable to be captured.
Raw password is never known or stored
balance between security and speed (for websites).
Hashing rather than encrypting passwords can help protect you against insider threats. Since the hash is a one-way process, for the most part users' stored, hashed passwords should not be decipherable. Rather, you can only run newly-inputted password attempts through the same has to see if the result is the same.
If you store encrypted passwords I would think that would imply that they could also be decrypted, which might be problematic if you have an untrustworthy insider.
This might be a good answer to the interview question, "How can you stop your DBA from making off with a list of your users’ passwords?"
I have posted a question here https://stackoverflow.com/questions/10308694/what-is-the-right-method-for-encoding-hashed-passwords-for-storage-in-ravendb with some sample code. Though the question itself might prove to be boneheaded, perhaps the code sample can be useful to you, if the c# code is intelligible.

Categories