Is this hashing function overkill - php

I recently began work on a project and it contains the following function to hash passwords :
function hash_password($password) {
$account_id = $this->account_id;
/*
* Cook up some randomness
*/
$password = str_rot13($password);
$random_chars = "1%#)(d%6^".md5($password)."&H1%#)(d%6^&HB(D{}*&$##$#FEFWB".md5($password)."``~~+_+_O(Ed##fvdfgRG:B>";
$salt = $account_id;
$salt = ((int)$salt * 123456789) * 1000;
$salt_len = strlen($salt);
for($i=0; $i <= $salt_len; $i++) {
$salt .= $random_chars[$i];
}
$salt = str_repeat($salt, 3);
return hash('sha256', base64_encode($password.$salt.$password), false);
}
*$account_id is unique to each user account.
My question is : Is this function any more secure than doing something as simple as :
$salt = sha1($account_id);
$hash = hash('sha256', base64_encode($password.$salt), false);
Cheers!

Using the account ID as a salt is probably not a good idea - if someone can steal your hashed passwords, then they can probably get the account ID's too. Having a more convoluted hash in code in this instance is therefore probably more secure, provided that the code is also well protected. Using a known random string as the salt in the code means that someone would have to hack both your data and your code in order to attack passwords - that has to be better than just having to attack the database alone.

Related

Trying to hash a password, but every time it just hashes to *0

I'm learning how to hash passwords using PHP for obvious security reasons. I have the two following functions for setting and checking hashes:
function password_encrypt($password)
{
$hash_format = "$2y$10$"; //blowfish
$salt_length = 22;
$unique_random_string = md5(uniqid(mt_rand(), true));
$base64_string = base64_encode($unique_random_string);
$modified_base_64_string = str_replace('+', '.', $base64_string);
$salt = substr($modified_base64_string, 0, $length);
$format_and_salt = $hash_format . $salt;
$hash = crypt($password, $format_and_salt);
echo $hash;
return $hash;
}
function password_check($password, $existing_hash)
{
$hash = crypt($password, $existing_hash);
if($hash === $existing_hash)
{
return true;
}
else
{
return false;
}
}
My issue is that every time I hash a password and send it off to the database it just gets stored as *0. I don't know where the *0 is coming from. Is there something wrong with what I'm doing?
Basically when I use it I just grab the entered password from $_POST and encrypt it using password_encrypt(). But it seems like it always comes out the other side as *0.
Short and Correct Answer
Don't roll your own cryptography, use an implementation that has already been vetted by security experts. For PHP 5.5 and above, this means password_hash() and password_verify(). For earlier versions of PHP, you can use password_compat (if your PHP version is older than 5.4, shame on you for running unsupported versions of PHP).
The Crypto Self-Education Answer
If you're dead set on writing your own cryptography code (for the learning experience, etc.), you must promise to never deploy your unproven implementation and make anything depend on it for security. Otherwise, just use password_hash() and password_verify() and stop reading right now.
There are a lot of problems with your code. Let's go down the line systematically, starting with password_encrypt(). (By the way, you aren't encrypting a password, you're hashing it.)
$unique_random_string = md5(uniqid(mt_rand(), true));
Yeah, NO. This is not a cryptographically secure way to generate a salt for a bcrypt hash. You should take a look at how password_compat implements this feature. Alternatively, see how random_compat generates random bytes for cryptographic purposes. (Also, please tell whomever advised you to use that one-liner to generate random strings that they are playing with fire.)
$unique_random_string = random_bytes(17);
Moving on...
$modified_base_64_string = str_replace('+', '.', $base64_string);
$salt = substr($modified_base64_string, 0, $length);
You forgot an underscore in the second variable name. Also, there is no variable named $length. These lines, corrected, look like so:
$modified_base_64_string = str_replace('+', '.', $base64_string);
$salt = substr($modified_base_64_string, 0, $salt_length);
Next,
$hash = crypt($password, $format_and_salt);
echo $hash;
return $hash;
Please don't leave your echo statements in your example code. Also, you should check for errors and throw an exception so your application doesn't chug happily along if bcrypt hashing fails.
$hash = crypt($password, $format_and_salt);
if ($hash === '*0') {
throw new Exception('Password hashing unsuccessful.');
}
return $hash;
Whew, almost done. Let's look at your password_check() function now:
if($hash === $existing_hash)
{
return true;
}
else
{
return false;
}
Don't compare cryptographic outputs (password hashes, MACs, etc.) using == or ===, or else you invite timing attacks into your application. Use hash_equals() for PHP 5.6, or a hash_equals() polyfill for earlier versions of PHP.
return hash_equals($hash, $existing_hash);
I hope this was an educational experience. Cryptography is hard, don't reinvent the wheel.

Store passwords of external database securely

I am creating a PHP application which can be installed on user's server but the administration is hosted on my server.
I need to store the password, username, db_name, host and port of database of the user. I think I should store in database (MySQL), but I don't know how to do securely.
Can you tell me please how can I store external passwords securely?
Thank you!
You need to have one secure key setup on main server (where database settings are stored) for example the password is b#auty! and on the other machine decrypt function with the same key to decrypt password. Now you can secure any string simply by
//url encrpytography
function encrypt($val, $key = 'b#auty!') {
$keySalt = $key;
$query = base64_encode(urlencode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($keySalt), $val, MCRYPT_MODE_CBC, md5(md5($keySalt))))); //this line of code encrypt the query string
return $query;
}
function decrypt($val, $key = 'b#auty!') {
$keySalt = $key; // same as used in encryptLink function
$queryString = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($keySalt), urldecode(base64_decode($val)), MCRYPT_MODE_CBC, md5(md5($keySalt))), "\0"); //this line of code decrypt the query string
//CHECK IF RETURN IS REAL LETTERS
if (preg_match('/^[a-z0-9 .\-]+$/i', $queryString)) {
} else {
$queryString = '';
}
return $queryString;
}
$encrypt = encrypt("string");
echo $encrypt;
$decrypt = decrypt($encrypt);
echo $decrypt
There is obviously more than one way to handle passwords in data stores. If you are very concerned that your password stores are never compromised, I highly recommend you look at this information:
http://www.openwall.com/articles/PHP-Users-Passwords
I always use this methodology now because it's as secure as one can get. It's free, and I have no affiliation with the author or his operation.

PHP BCrypt output correct?

New to stackoverflow :)
I just now started to use a bcrypt function I've found on some site about security. I've never really worried about the output from this until our technician at work said this to me:
The salt seems to always be in the front of every password.
Is this correct or have I made a major boo boo? :)
The code I use is this:
<?php
function bcrypt($password, $salt, $rounds=12) {
// Check if bcrypt is available on the server
if (CRYPT_BLOWFISH != 1) {
throw new Exception("bcrypt stöds inte. Se http://php.net/crypt");
return;
}
// Check that rounds are within the allowed range
if ($rounds < 4)
$rounds = 4;
else if ($rounds > 12)
$rounds = 12;
// Create a prefix to tell the crypt that we want to use bcrypt
$salt_prefix = sprintf('$2a$%02d$', $rounds);
// Check if the salt contains invalid characters:
if (!preg_match('#^[A-Za-z0-9./]{22}$#', $salt)) {
// The salt is not bcrypt-safe. Redo to 22 characters (A-Za-z0-9. /)
$new_salt = base64_encode($salt);
if (strlen($new_salt) < 22)
$new_salt .= base64_encode(md5($salt));
$salt = substr($new_salt, 0, 22);
$salt = str_replace(array('+', '-'), '.', $salt);
$salt = str_replace(array('=', '_'), '/', $salt);
}
// hash the password with bcrypt
return crypt($password, $salt_prefix.$salt);
}
// Examples :
echo "Bcrypt: ". bcrypt('abc', 'QyrjMQfjgGIb4ymtdKQXIr', 12);
?>
This will output:
Bcrypt: $2a$12$QyrjMQfjgGIb4ymtdKQXIewDBqhA3eNppF8qOrMhidnEbzNvmHqhy
As you can see the salt is inside the password now "bold text":
Salt = QyrjMQfjgGIb4ymtdKQXIr
pass = $2a$12$QyrjMQfjgGIb4ymtdKQXI
ewDBqhA3eNppF8qOrMhidnEbzNvmHqhy
This seem to be the same every time regardless of salt. Salt is always included except the last character?
You can test an existing bcrypt hash with lots of tools online, like this bcrypt generator

Validate a password against an SSHA256 hash in PHP

For authentification with Dovecot, I use SSHA256 hashes but I have no clue how to validate a given password against the existing hash. The following PHP functions (found them in the web) are used to create the SSHA256 hash:
function ssha256($pw) {
$salt = make_salt();
return "{SSHA256}" . base64_encode( hash('sha256', $pw . $salt, true ) . $salt );
}
function make_salt() {
$len = 4;
$bytes = array();
for ($i = 0; $i < $len; $i++ ) {
$bytes[] = rand(1,255);
}
$salt_str = '';
foreach ($bytes as $b) {
$salt_str .= pack('C', $b);
}
return $salt_str;
}
Example output: {SSHA256}lGq49JTKmBC49AUrk7wLyQVmeZ7cGl/V13A9QbY4RVKchckL
Do I have to extract the salt, but how?
I totally lost the way for solving the problem, has anyone a hint for this?
Thanks to everyone for helping!
Oh and sorry, I have to use SSHA256, because Dovecot 1.2.15 supports only those schemes:
CRYPT MD5 MD5-CRYPT SHA SHA1 SHA256 SMD5 SSHA SSHA256 PLAIN CLEARTEXT CRAM-MD5 HMAC-MD5 DIGEST-MD5 PLAIN-MD4 PLAIN-MD5 LDAP-MD5 LANMAN NTLM OTP SKEY RPA
You should not be using the SHA family for password hashing. They are fast and designed for hashing files at speed. You need pashword hashing to be expensive. Use bcrypt, PHPass or just use this class, which I rolled myself (but not until you learn to pick holes in it):
class PassHash {
public static function rand_str($length) {
$total = $length % 2;
$output = "";
if ($total !== 0) {
$count = floor($length / 2);
$output .= ".";
} else $count = $length / 2;
$bytes = openssl_random_pseudo_bytes($count);
$output .= bin2hex($bytes);
// warning: prepending with a dot if the length is odd.
// this can be very dangerous. no clue why you'd want your
// bcrypt salt to do this, but /shrug
return $output;
}
// 2y is an exploit fix, and an improvement over 2a. Only available in 5.4.0+
public static function hash($input) {
return crypt($input, "$2y$13$" . self::rand_str(22));
}
// legacy support, add exception handling and fall back to <= 5.3.0
public static function hash_weak($input) {
return crypt($input, "$2a$13$" . self::rand_str(22));
}
public static function compare($input, $hash) {
return (crypt($input, $hash) === $hash);
}
}
You have to hash the plaintext given and compare that hash against one you have stored. The salts are stored in the hashes, and should be random. If you like, add a pepper. You should also make the workrate variable, so that you can change the workrate at any moment when needed and still have your system work.
If, like you say, you have no way of implementing this, you can unpack the hash as follows:
function unpack_hash($hash) {
$hash = base64_decode($hash);
$split = str_split($hash, 64);
return array("salt" => $split[1], "hash" => $split[0]);
This is because SHA256 is 256 bits, or 64 hex characters. You can just always assume the first 64 chars are the hash
You need to store the salt along with the hashed value.
When you need to validate the password, you simply calculate the hash again with the user input password + the stored salt. If the hashes match, the user entered the correct password.
For your format, use base64_decode first, the last 4 bytes of the result will be the salt.

crypt() function not giving proper hashes

I have made an password hashing script using this and this, i am getting it to work correctly except some times the crypt function is giving hash as "*0", and then it fails.
PHP Codes
$password='password';
$salt = '$2y$07$';
$salt .= base64_encode(mcrypt_create_iv(16, MCRYPT_DEV_RANDOM));
$salt .='$$';
$password_hash = crypt($password, $salt)';
echo $password_hash.'<br />';
Using above i am getting values as
$salt = '$2y$07$8K3i8rJ7n7bsJA36CfbabQ==$$';
$crypt_password = $password_hash;
$crypt_password = '$2y$07$8K3i8rJ7n7bsJA36CfbabO9ojj2hl61azl8CubJQhRTgla4ICiCVC';
if (crypt($password,$crypt_password)===$crypt_password)
{
echo 'password verified';
}
else{
echo 'password NOT verified';
}
Please see and suggest any possible way to make it work correctly.
Thanks.
The problem is that base64_encode may generate a string with '+' symbol, which is considered an incorrect salt by crypt function.
var_dump your $salt along with $password, and you'll see that each time + character is used in the salt, crypt function will return a '*0' string - the sign of failure.
One possible way of solving it is replacing all '+' signs with '.':
$salt = str_replace('+', '.', $salt);

Categories