0

Possible Duplicate:
Secure hash and salt for PHP passwords

For the encrypting of the password in the php file, I want to change to sha256 or md5 instead of using sha1 as iIwent to research online and they say sha1 is not so secure.

How do I change in the php file?

<?php

class DB_Functions {

private $db;

//put your code here
// constructor
function __construct() {
    require_once 'DB_Connect.php';
    // connecting to database
    $this->db = new DB_Connect();
    $this->db->connect();
}

// destructor
function __destruct() {

}

/**
 * Storing new user
 * returns user details
 */
public function storeUser($name, $nric, $email, $license, $address, $postal_code, $password) {
    $hash = $this->hashSSHA($password);
    $encrypted_password = $hash["encrypted"]; // encrypted password
    $salt = $hash["salt"]; // salt
    $result = mysql_query("INSERT INTO users(name, nric, email, license, address, postal_code, encrypted_password, salt, created_at) VALUES('$name', '$nric', '$email', '$license', '$address', '$postal_code', '$encrypted_password', '$salt', NOW())");
    // check for successful store
    if ($result) {
        // get user details 
        $uid = mysql_insert_id(); // last inserted id
        $result = mysql_query("SELECT * FROM users WHERE uid = $uid");
        // return user details
        return mysql_fetch_array($result);
    } else {
        return false;
    }
}

/**
 * Get user by nric and password
 */
public function getUserByNricAndPassword($nric, $password) {
    $result = mysql_query("SELECT * FROM users WHERE nric = '$nric'") or die(mysql_error());
    // check for result 
    $no_of_rows = mysql_num_rows($result);
    if ($no_of_rows > 0) {
        $result = mysql_fetch_array($result);
        $salt = $result['salt'];
        $encrypted_password = $result['encrypted_password'];
        $hash = $this->checkhashSSHA($salt, $password);
        // check for password equality
        if ($encrypted_password == $hash) {
            // user authentication details are correct
            return $result;
        }
    } else {
        // user not found
        return false;
    }
}

/**
 * Check user is existed or not
 */
public function isUserExisted($nric) {
    $result = mysql_query("SELECT nric from users WHERE nric = '$nric'");
    $no_of_rows = mysql_num_rows($result);
    if ($no_of_rows > 0) {
        // user existed 
        return true;
    } else {
        // user not existed
        return false;
    }
}

/**
 * Encrypting password
 * @param password
 * returns salt and encrypted password
 */
public function hashSSHA($password) {

    $salt = sha1(rand()); //algorithm hash
    $salt = substr($salt, 0, 10);
    $encrypted = base64_encode(sha1($password . $salt, true) . $salt);
    $hash = array("salt" => $salt, "encrypted" => $encrypted);
    return $hash;
}

/**
 * Decrypting password
 * @param salt, password
 * returns hash string
 */
public function checkhashSSHA($salt, $password) {

    $hash = base64_encode(sha1($password . $salt, true) . $salt);

    return $hash;
}

}

?> 
Community
  • 1
  • 1
Twister
  • 199
  • 3
  • 9
  • 19
  • http://php.net/manual/en/function.hash.php ? – j0k Sep 06 '12 at 08:43
  • Hi there. 1. This isn't your file is it? There are various parts in the file (and probably the database) where you will have to change in order to use a different hashing algorithm, you should really look through the file and work out what it does to make sure it works properly. 2. If you're worried about security then you should really use BCRYPT to hash passwords. BCRYPT is slow to work out the hash and therefore will take potential brute force attacks much longer. – Thomas Clayson Sep 06 '12 at 08:45
  • Also see Openwall's [PHP password hashing framework](http://www.openwall.com/phpass/) (PHPass). Its portable and hardened against a number of common attacks on user passwords. The guy who wrote the framework (SolarDesigner) is the same guy who wrote [John The Ripper](http://www.openwall.com/john/) and sits as a judge in the [Password Hashing Competition](http://password-hashing.net/). So he knows a thing or two about attacks on passwords. – jww Oct 12 '14 at 00:41

5 Answers5

6

The most secure way of hashing passwords, would be to use BCrpyt
MD5, SHA1, SHA256 is considered not secure.

For more information on this matter, see this post on security: https://security.stackexchange.com/questions/211/how-to-securely-hash-passwords

For implementing BCrpyt password hashing see: How do you use bcrypt for hashing passwords in PHP?

Community
  • 1
  • 1
Kao
  • 2,242
  • 3
  • 22
  • 31
  • I see. Im am new at php as well as java. Any samples on how to hash it in php? – Twister Sep 06 '12 at 08:58
  • Edited to use BCrypt and included an implementation link. – Kao Sep 06 '12 at 09:06
  • BCrypt won't save you when you are doing things the wrong way. A well setup SHA-256 (e.g. with salting) will be next to uncrackable for the next years, while a badly used BCrypt will be susceptible to rainbow table attacks. A password *barely ever* gets cracked by decrypting the hash, except for unhashed common passwords. Usually, the problem is that the *surrounding code* has flaws, such as not using salts. Instead of wasting too much time on choosing hash algorithms, instead pay *extra attention* that you are using them effectively. – Has QUIT--Anony-Mousse Sep 07 '12 at 14:19
  • As you said it yourself, for the next years. Which means, within the next 3 - 4 years. That would require him to recode the hashing at that point, which would make no sense, and which is why sha-256 is no longer recommended. But I agree with your statement. – Kao Sep 07 '12 at 16:14
  • 1
    @Anony-Mousse - It's exactly opposite, SHA-256 is prone to rainbow-table attacks (or brute forcing if a salt was used), because it can be calculated much [too fast](http://hashcat.net/oclhashcat-lite/#performance) with dedicated hardware. The advantage of Bcrypt is, that you can choose a **cost factor** which determines the time needed for the calculation, so a rainbow-table will become impracticable. You are right saying, that SHA-256 is a safe algorithm, but it is inappropriate for hashing passwords, because it can be brute-forced ways too fast. – martinstoeckli Sep 14 '12 at 06:50
  • Well, since your operating system probably uses this for hashing your administrator passwords, you are busted then anyway. SHA-256 is good enough, if you use it right. Better pay *more attention to using it right*. – Has QUIT--Anony-Mousse Sep 14 '12 at 06:53
  • @Anony-Mousse Why suggest something that may be good enough (if you implement it correctly, which no one does) rather than something that's definitely good enough (and easy to implement correct)? SHA-256 alone is nowhere near good enough. You need to salt the password (correctly, which a lot of people get wrong). You also need enough iterations (which a lot of people get wrong). Pretty much the only thing you can get wrong with bcrypt is not using a random salt (which would be a problem with PBKDF2-SHA256 too). – Brendan Long Sep 20 '12 at 20:34
  • 1
    Well, just you wait how many ways people find to screw up with BCrypt. PHP users are very creative. – Has QUIT--Anony-Mousse Sep 20 '12 at 23:53
3

BCrypt is the way to go when it comes to encrypting your passwords in PHP. Here is some code that should help you along the way:

<?php
/*
By Marco Arment <me@marco.org>.
This code is released in the public domain.

THERE IS ABSOLUTELY NO WARRANTY.

Usage example:

// In a registration or password-change form:
$hash_for_user = Bcrypt::hash($_POST['password']);

// In a login form:
$is_correct = Bcrypt::check($_POST['password'], $stored_hash_for_user);

// In a login form when migrating entries gradually from a legacy SHA-1 hash:
$is_correct = Bcrypt::check(
$_POST['password'],
$stored_hash_for_user,
function($password, $hash) { return $hash == sha1($password); }
);
if ($is_correct && Bcrypt::is_legacy_hash($stored_hash_for_user)) {
$user->store_new_hash(Bcrypt::hash($_POST['password']));
}

*/

class Bcrypt
{
    const DEFAULT_WORK_FACTOR = 8;

    public static function hash($password, $work_factor = 0)
    {
        if (version_compare(PHP_VERSION, '5.3') < 0) throw new Exception('Bcrypt requires PHP 5.3 or above');

        if (! function_exists('openssl_random_pseudo_bytes')) {
            throw new Exception('Bcrypt requires openssl PHP extension');
        }

        if ($work_factor < 4 || $work_factor > 31) $work_factor = self::DEFAULT_WORK_FACTOR;
        $salt =
            '$2a$' . str_pad($work_factor, 2, '0', STR_PAD_LEFT) . '$' .
            substr(
                strtr(base64_encode(openssl_random_pseudo_bytes(16)), '+', '.'),
                0, 22
            )
        ;
        return crypt($password, $salt);
    }

    public static function check($password, $stored_hash, $legacy_handler = NULL)
    {
        if (version_compare(PHP_VERSION, '5.3') < 0) throw new Exception('Bcrypt requires PHP 5.3 or above');

        if (self::is_legacy_hash($stored_hash)) {
            if ($legacy_handler) return call_user_func($legacy_handler, $password, $stored_hash);
            else throw new Exception('Unsupported hash format');
        }

        return crypt($password, $stored_hash) == $stored_hash;
    }

    public static function is_legacy_hash($hash) { return substr($hash, 0, 4) != '$2a$'; }
}


// =============================================================================
// Or, if you don't want the class structure and just want standalone functions:
// =============================================================================

function bcrypt_hash($password, $work_factor = 8)
{
    if (version_compare(PHP_VERSION, '5.3') < 0) throw new Exception('Bcrypt requires PHP 5.3 or above');

    if (! function_exists('openssl_random_pseudo_bytes')) {
        throw new Exception('Bcrypt requires openssl PHP extension');
    }

    if ($work_factor < 4 || $work_factor > 31) $work_factor = 8;
    $salt =
        '$2a$' . str_pad($work_factor, 2, '0', STR_PAD_LEFT) . '$' .
        substr(
            strtr(base64_encode(openssl_random_pseudo_bytes(16)), '+', '.'),
            0, 22
        )
    ;
    return crypt($password, $salt);
}

function bcrypt_check($password, $stored_hash, $legacy_handler = NULL)
{
    if (version_compare(PHP_VERSION, '5.3') < 0) throw new Exception('Bcrypt requires PHP 5.3 or above');

    if (bcrypt_is_legacy_hash($stored_hash)) {
        if ($legacy_handler) return call_user_func($legacy_handler, $password, $stored_hash);
        else throw new Exception('Unsupported hash format');
    }

    return crypt($password, $stored_hash) == $stored_hash;
}

function bcrypt_is_legacy_hash($hash) { return substr($hash, 0, 4) != '$2a$'; }
crmpicco
  • 16,605
  • 26
  • 134
  • 210
  • so i will just have to change my php function `public function hashSSHA($password) and public function checkhashSSHA($salt, $password)` to `function bcrypt_hash , function bcrypt_check and function bcrypt_is_legacy_hash` ? How to implement in? – Twister Sep 06 '12 at 09:51
  • You could do something like `bcrypt_hash('yourpassword')` and that will return you a BCrypt'd Salt'd password. There is also usage examples at the top of the class in the comments. – crmpicco Sep 06 '12 at 09:53
  • The simplest possible way is to just search-and-replace "sha1" for "bcrypt_hash" and it should work exactly the same, as long the database column is more than just a VARCHAR(30). You need openssl enabled for this code. – SilverbackNet Sep 09 '12 at 05:19
1

Do not spend to much time playing around with different hash algorithms and your own perfect way of storing them. Chances are that you make some mistake here, and the best hashing algorithm cannot save you.

I strongly advise people to stick to the standard libraries. They have pretty good functionality that is used by the host system anyway. This means in particular the crypt function, which is likely used heavily by various parts of your operating system.

Now some people will get a heart attack when I mention crypt. And this is good, because it means they are just repeating information from the original UNIX days again, and have not understood much. Modern crypt can do much more than DES. Just don't use it with DES.

Here is part of the crypt man page on my Linux system (but this is also supported by BSD). All of this should be directly available in PHP, too:

          ID  | Method
          ---------------------------------------------------------
          1   | MD5
          2a  | Blowfish (not in mainline glibc; added in some
              | Linux distributions)
          5   | SHA-256 (since glibc 2.7)
          6   | SHA-512 (since glibc 2.7)

   So   $5$salt$encrypted   is   an   SHA-256   encoded    password    and
   $6$salt$encrypted is an SHA-512 encoded one.

   "salt" stands for the up to 16 characters following "$id$" in the salt.
   The encrypted part of the password string is the actual computed  pass-
   word.  The size of this string is fixed:

   MD5     | 22 characters
   SHA-256 | 43 characters
   SHA-512 | 86 characters

The massive benefit you get from using this scheme is that you can in fact have different schemes in effect in your system.

Say you have some users who set their password in a time where you were still using MD5. However, any new password should be encrypted using SHA-256. And maybe in a few years, you want to slowly migrate to yet another standard, maybe Bcrypt. No problem. It just needs a new ID. And these hashes are probably supported by all the standard software you have. Need them as unix logins? No problem. Apache HTTP authentication? no problem. Because it's using the operating system standard.

And on verification, it will be tested against the scheme that was in use when the password was last set. So it is backwards compatible, and forwards compatible.

If you want to migrate to a new scheme, say SHA-3 when it is out, you can just change the default hash to the latest, then ask the users to set a new password, and at some point disable all passwords that have the old hash ID. It makes tons of sense to store an ID along with the hash.

All you need to do to use SHA-256 scheme, is to generate a Hash that has the scheme $5$<16-chars-of-salt>$. If you want SHA-512, use $6$<16-chars-of-salt>$.

It's very simple code:

crypt("Hello",'$6$CygnieHyitJoconf$')

will produce

$6$CygnieHyitJoconf$vkGJm.nLrFhyWHhNTvOh9fH/k7y6k.8ed.N7TqwT93hPMPfAOUsrRiO3MmQB5xTm1XDCVlW2zwyzU48epp8pY/

A properly salted SHA-512 password hash. Don't reinvent the wheel.

Has QUIT--Anony-Mousse
  • 76,138
  • 12
  • 138
  • 194
0

you can use

$encrypted = base64_encode(hash('sha256',$password . $salt));

instead of

$encrypted = base64_encode(sha1($password . $salt, true));

in function

hashSSHA   
Poonam
  • 4,591
  • 1
  • 15
  • 20
0

You can change hash function to sha256, md5, or anything, but it will not work well if your DB is already filled with sha1-hashed passwords. In this case there's no way to change hash function without discarding legacy datas.

Mics
  • 1,420
  • 14
  • 19
  • I can just delete all the data that already using sha1 password and then recreate new data with the new hash function. Right? – Twister Sep 06 '12 at 08:52
  • Of course if you can do that. – Mics Sep 06 '12 at 08:56
  • **YES** there is a way. Have a look how `crypt` solves it, and allows to coexistence of different hashes. And no, you usually cannot regenerate the data, because you don't want to store the source data (which would be the plaintext passwords) ... the key idea is to include the encryption *algorithm* in the hash. – Has QUIT--Anony-Mousse Sep 07 '12 at 14:47