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.
Related
Actually I read many post related to the algorithm for use like md5, sha1 and so on. But I am still not sure which one is the secure and the best one to use nowadays. I am beginner with web development and I am asking all of the best programmers around the world to teach and show me. I hope you guys can give me the choice and example for using it. Thank You
Incidentally: How to safely store your users' passwords in 2016.
Your choices are:
Argon2 (requires PHP 7.2 or a PHP extension)
Scrypt (requires PHP extension)
Bcrypt
If you really need to, also feel free to consider PBKDF2.
The old standby: Bcrypt
Given that you're a beginner, you should be writing your password validation like this:
// Creating your hashed password:
$hash = password_hash($userPassword, PASSWORD_DEFAULT);
// Checking a user-supplied password against a stored hash:
if (password_verify($userPassword, $hash)) {
// Login successful.
if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
// Recalculate a new password_hash() and overwrite the one we stored previously
}
}
Downside to bcrypt:
Passwords over 72 characters are truncated.
Passwords with a NUL byte will truncate.
A stop-gap that works around these limitations is built into Password Lock: It pre-hashes passwords with SHA384 then base64-encodes the raw hash before passing to PHP's password API.
First, create an encryption key and store it outside your document root. (Otherwise, a hacker can just steal the key.)
$newKey = \Defuse\Crypto\Key::createNewRandomKey();
file_put_contents(
'/outside/document/root/enckey.txt',
$newKey->saveToAsciiSafeString()
);
Now, you can use this key in conjunction with your passwords:
$key = Key::loadFromAsciiSafeString(
file_get_contents('/outside/document/root/enckey.txt')
);
// Hashing a password with PasswordLock:
$storeMe = PasswordLock::hashAndEncrypt($_POST['password'], $key);
// Verifying a password with PasswordLock:
if (PasswordLock::decryptAndVerify($_POST['password'], $storeMe, $key)) {
// Success!
}
You can now use Argon2 with password_hash() in PHP 7.2
The new standard: Argon2 (via Libsodium)
Unless you're on PHP 7.2 or higher, you'll need to install libsodium and the PHP extension to use Argon2. Password hashing is one of the features that is not provided by sodium_compat.
// Password hashing:
$hash_str = sodium_crypto_pwhash_str(
$password,
SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
);
// Password verification:
if (sodium_crypto_pwhash_str_verify($hash_str, $password)) {
// recommended: wipe the plaintext password from memory
sodium_memzero($password);
// Password was valid.
} else {
// recommended: wipe the plaintext password from memory
sodium_memzero($password);
// Password was invalid.
}
Intermediate: Scrypt
You'll need the scrypt extension which is available through PECL:
pecl install scrypt
echo "extension=scrypt.so" > /etc/php5/mods-available/scrypt.ini
php5enmod scrypt
Once that's installed, using it is fairly straightforward:
// Hashing:
$hash = \Password::hash($userProvidedPassword);
// Validation:
if (\Password::check($userProvidedPassword, $hash)) {
// Logged in successfully.
}
The only reason to really use scrypt is compatibility; at this point, go with either Argon2 or bcrypt.
Acceptable but not Great: PBKDF2
I highly recommend going with Defuse Security's cross-platform Password Hashing library if you need PBKDF2. (You should consider just using password_*, however!)
$hash = PasswordStorage::create_hash($password);
if (PasswordStorage::verify_password($password, $hash)) {
// Success
}
Any of the above choices are acceptable. Argon2 is probably the most secure, but it's not widely available in PHP yet. Anything absent from this list should be regarded with a healthy dose of skepticism.
Important is, that the algorithm offers a cost factor, which controls the necessary time to calculate a hash. The more time you can invest in calculating a single hash, the more expensive brute-forcing will become (e.g. 100 Giga MD5 per second vs 10 BCrypt per second).
Today recommended algorithms are BCrypt, PBKDF2 and SCrypt. The algorithm BCrypt is supported by PHP, a wrapper function takes care of the generation of a salt and is future proof.
// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_DEFAULT);
// 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);
i'm testing several combinations of sha1 and md5:
<?php
$test = 'fail test';
echo nl2br ("Text: $test\n");
echo nl2br ("md5: ".md5($test)."\nsha1: ".sha1($test)."\nsha1(md5): ".sha1(md5($test))."\nmd5(sha1): ".md5(sha1($test)));
?>
Output:
Text: fail test
md5: 748410d0085967c496d54dd8fcbecc96
sha1: d730125e8cb8576459173655148fb6896ef44c09
sha1(md5): faa3ebeecfec45e509e93e6b245a69e2a78785ea
md5(sha1): b48e89b85c350c91eb302c1de96d4249
Which one better, or maybe user something else ? If yes, what then ?
Both of them are cryptographic hash functions that operate 1-way only, the main difference being that MD5 output size is 128 bits whereas SHA-1 is 160 bits. In brief, I don't see they are much different to use despite MD5 is more common these days.
Curiously, I can't really see how md5($text) is different from md5(sha($text)) when they all encrypted to a 32 character-long string, what about md5($text."token") for example?
And, what do you mean by better? Is it more good looking or more security? See bcrypt if you prefer security :) Wikipedia: http://en.wikipedia.org/wiki/Bcrypt
Hashing a hash adds no extra security. (In fact, it might make it worse if the person has a hash-of-hash lookup table.)
The best hash will be the one that is computationally the most expensive to perform without any vulnerabilities. I would hash passwords with at least sha-256.
Always hash your passwords with a salted key. This key should be unique per password. It doesn't need to be stored privately. The purpose of a salted password is that the hacker who gained access to your database cannot simply compare the hash with a known list of hashes that correspond to common passwords. Instead, he must try to brute force the password by trying every possible password.
By using a unique salt per password, you guarantee that each hash in the database is different, even if they use the same password.
To salt a password, simply create a random string of characters and append it to the password. Here's a sample hash with a 48-bit salt and sha-256:
function make_password($password)
{
# random 48-bit salt (8 chars when base64 encoded)
$salt = base64_encode(pack('S3', mt_rand(0,0xffff), mt_rand(0,0xffff), mt_rand(0, 0xffff)));
return $salt.hash('sha256', $salt.$password);
}
function check_password($password, $hash)
{
$salt = substr($hash, 0, 8);
return hash('sha256', $salt.$password) == substr($hash, 8);
}
$password = 'password';
$hash = make_password('password');
echo $hash."\n";
var_dump(check_password('password', $hash));
var_dump(check_password('wrong', $hash));
Every time you run it, the hash will be different. To validate a password, you select the row where the username matches, and then call check_password($password_from_user, $hash_from_db).
Here's a sample output:
AzrD1jZzc693714a43ad5dfd4106c0a620ef23ff9915070711fa170a6670b8164862b496
bool(true)
bool(false)
You can use a larger salt or a stronger hashing algorithm if you prefer. But at minimum, I would use something like the above.
You should salt your passwords, ALWAYS. This doesn't stop brute force through a login form but if someone managed to get the details, it would be much harder to crack (rainbow tables would be useless unless they manage to get your salt too)
Essentially, if you adding onto the original data or mangling in a controlled way, it will make security a little better. No-one can ever reverse a hash but they can find other inputs thats match the hash. Mangling the user input will make it harder to login for the hackers.
for example, if a user's pass is 123456, if you add a salt of "salt" to it so it becomes 123456salt, the MD5 of this would be 207acd61a3c1bd506d7e9a4535359f8a. A hacker could crack this to become 123456salt but when it comes to using that on your login form, your code will add salt again and the login will fail.
I'd like to use Portable PHP password hashing framework to hash passwords. But I find that its demos don't use salt for hashing a password. But it use a dummy salt for checking password which I find it strange and I don't understand this idea at all,
$dummy_salt = '$2a$08$1234567890123456789012';
if (isset($dummy_salt) && strlen($hash) < 20)
$hash = $dummy_salt;
I wonder, if I want to use convention method which I can generate the unique salt and store it for each user in my database, how can I use Portable PHP password hashing framework to generate salts?
This is the function I use to hash passwords but I have been told that sha512 has the same issue as sha1, wise to trust the expert like Portable PHP password hashing framework,
function hash_sha512($phrase,&$salt = null)
{
//$pepper = '!##$%^&*()_+=-{}][;";/?<>.,';
if ($salt == '')
{
$salt = substr(hash('sha512',uniqid(rand(), true).PEPPER_KEY.microtime()), 0, SALT_LENGTH);
}
else
{
$salt = substr($salt, 0, SALT_LENGTH);
}
return hash('sha512',$salt.PEPPER_KEY.$phrase);
}
Let me know if you have any idea. Thanks.
From the phpass article linked to from that page:
Besides the actual hashing, phpass
transparently generates random salts
when a new password or passphrase is
hashed, and it encodes the hash type,
the salt, and the password stretching
iteration count into the "hash
encoding string" that it returns. When
phpass authenticates a password or
passphrase against a stored hash, it
similarly transparently extracts and
uses the hash type identifier, the
salt, and the iteration count out of
the "hash encoding string". Thus, you
do not need to bother with salting and
stretching on your own - phpass takes
care of these for you.
...so it's not surprising that the examples don't use salting! You may be over-seasoning your code.
The code sample with the dummy salt is an example of how to prevent a timing attack by making sure that whether a user exists or not, the validation of the user takes the same amount of time, effectively by doing a dummy authentication for non-existent users. It needs a dummy salt because if the user doesn't exist, it won't have a stored salt to use.
I have a password being passed from my iPhone app to the database via a php script, user.php.
The variable $pass is populated by the following:
$pass = str_replace("'", "", $_REQUEST['pass']);
How can I encrypt this before it's inserted into my database? I've read a little about the different techniques, but looking for the best way to manage this.
Thanks to everyone.
While the answer below is technically still correct, php has new recommendations with regards to the hashing algorithms to use. Their recommendation, as of php >= 5.5.0, is to use the password_hash and password_verify functions to hash and verify hashed passwords . As an added benefit, these functions automatically include an individualized salt as part of the returned hash, so you don't need to worry about that explicitly.
If you don't care about retrieving the actual password's value (from the database encrypted value), you can run a one-way hash algorithm on it (such as sha1). This function will return a specific length string (hash) which cannot be used to find the original string (theoretically). It is possible that two different strings could create the same hash (called a collision) but this shouldn't be a problem with passwords.
Example:
$pass = sha1($_REQUEST['pass']);
One thing, to make it a little more secure is to add a salt to the hash and run the hash function again. This makes it more difficult to generate a password hash maliciously since the salt value is handled server-side only.
Example:
$pass = sha1(sha1($_REQUEST['pass']).sha1("mySalt#$#(%"));
Use php's crypt library. Md5 is not encryption, it is hashing.
Also, salt your passwords. Why?
This answer
Another good answer
First, you should create a random user salt. Then you should store that and the password hash in the database.
$salt = md5(unique_id().mt_rand().microtime());
$pass = sha1($salt.$_REQUEST['pass']);
and save the $salt and $pass in the database. Then when they go to login you look up their row and check the hash:
$user = query('SELECT * FROM `user` WHERE username = ?', array($_REQUEST['username']));
if($user)
{
// If the password they give maches
if($user->pass === sha1($user->salt. $_REQUEST['pass']))
{
// login
}
else
{
// bad password
}
}
else
{
// user not found
}
Creating a user salt for each account insures rainbow tables are useless and anyone that broken into your server would have to brute-force each password.
Use crypt with some salt. Such as
$user = strip_tags(substr($_REQUEST['user'],0,32));
$plain_pw = strip_tags(substr($_REQUEST['pass'],0,32));
$password = crypt(md5($plain_pw),md5($user));
as on http://www.ibm.com/developerworks/opensource/library/os-php-encrypt/
Most basic: Hash it with MD5 or SHA1
$newpass = md5($_REQUEST['pass']);
or
$newpass = sha1($_REQUEST['pass']);
Recently I started storing the username hashed as well, so login attempts are secure using only hashed data for comparisons.
You can "salt" the hashes with extra data so if they are compromised, it's value cannot be found (try googling some simple hashed words).. i.e. use a site-wide string just to alter the standard hash like md5("mySiteSalt!!" . $_REQUEST['pass']); or something more advanced.
You should use SHA1 to hash your passwords for storage in the database. It's the simplest, yet most effective way to store passwords:
$password = sha1($password);
It's also exceptionally safe. Though the integrity of it is beginning to creep, it's rather easy to upgrade this function to SHA-256 (which is incredibly secure).
To find out why md5, sha1 and their speedy friends might not be a good idea, you should read the post Enough With The Rainbow Tables: What You Need To Know About Secure Password Schemes by Thomas Ptacek. The gist:
Finally, we learned that if we want to
store passwords securely we have three
reasonable options: PHK’s MD5 scheme,
Provos-Maziere’s Bcrypt scheme, and
SRP. We learned that the correct
choice is Bcrypt.
Note: it's PHK, not php.
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.