0

There is a php script I wrote with the help of a tutorial. In the script when a user registers his password is encrypted with sha1 and salt, which works perfectly fine. The code:

public function storeUser($name, $email, $password, $studentID) {
    $uuid = uniqid('', true);
    $hash = $this->hashSSHA($password);
    $encrypted_password = $hash["encrypted"]; // encrypted password
    $salt = $hash["salt"]; // salt

    $stmt = $this->conn->prepare("INSERT INTO users(unique_id, name, email, encrypted_password, salt, created_at) VALUES(?, ?, ?, ?, ?, ?, NOW())");
    $stmt->bind_param("sssss", $uuid, $name, $email, $encrypted_password, $salt);
    $result = $stmt->execute();
    $stmt->close();

    // check for successful store
    if ($result) {
        $stmt = $this->conn->prepare("SELECT * FROM users WHERE email = ?");
        $stmt->bind_param("s", $email);
        $stmt->execute();
        $user = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        return $user;
    } else {
        return false;
    }
}

and the hashSSHA() function:

public function hashSSHA($password) {

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

Now i have a problem with logging in. I have a function to check hash, but i cannot figure out how to pass the salt parameter to check for password as well:

public function getUserByEmailAndPassword($email, $password) {

    $stmt = $this->conn->prepare("SELECT * FROM users WHERE email = ?");

    $stmt->bind_param("s", $email);

    if ($stmt->execute()) {
        $user = $stmt->get_result()->fetch_assoc();
        $stmt->close();
        return $user;
    } else {
        return NULL;
    }
}

public function checkhashSSHA($salt, $password) {

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

    return $hash;
}

Can you help me to figure out how to pass the salt parameter in checkhashSSHA() function so i can check for password when logging in, in getUserByEmailAndPassword() function? Thank you.

Bill Hicks
  • 105
  • 1
  • 4
  • 15
  • 2
    You shouldn't roll your own crypto stuff. Please use the password_hash library in PHP instead http://php.net/manual/en/function.password-hash.php. If you need to be compatible with PHP < 5.5 you need https://github.com/ircmaxell/password_compat – JimL Dec 24 '15 at 20:35
  • @JimL Hmm, I am kinda unfamiliar with new PHP stuff, so can you help me out here? Thanks. – Bill Hicks Dec 24 '15 at 20:37
  • Save the hash you get from this: `$hash = password_hash($submittedPassword, PASSWORD_DEFAULT);`. Check if valid: `if(password_verify($submittedPassword, $storedHash)) { /* user authenticated - do stuff */ }` – JimL Dec 24 '15 at 20:40
  • I'd read this http://stackoverflow.com/questions/2772014/is-sha-1-secure-for-password-storage about using sha1. Use something more of *this century*. – Funk Forty Niner Dec 24 '15 at 20:47
  • @JimL Oh, I should definitely use this, thanks a lot. :) – Bill Hicks Dec 24 '15 at 20:47
  • @BillHicks Won't argue with you there. Much easier and much more secure. Win win :) – JimL Dec 24 '15 at 20:49
  • @JimL The tutorial was 2012, so yeah. Thank you, again. – Bill Hicks Dec 24 '15 at 20:50

2 Answers2

0

salt is attached to the end of password:

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

last 10 character is the salt.

Although, this is maybe not good way to handle the password hashing, but if you need to follow this path, you need to:

  1. keep salt in a separated column, read it from db and rehash new password with same salt and compare
  2. use part of password or username as salt. then you have access to the salt as soon as user try to enter login info. ex:

use user+password first 10 char as salt:

$salt=substr(username."!".password,10)
Ali Nikneshan
  • 3,500
  • 27
  • 39
  • But don't use SHA1 and don't just concatenate the salt with the password, use an HMAC. Better yet preferably use PBKDF2 and also add the iteration count to the saved value: salt|iterations|hash. – zaph Dec 24 '15 at 20:57
  • @zaph fully agreed. Using self created methods for hashing is discouraged, but OP trying to use a tutorial not in production env. – Ali Nikneshan Dec 24 '15 at 20:59
  • 1
    @AliNikneshan many use tutorials to hack their way to production code... ^^ – JimL Dec 24 '15 at 21:15
  • Instructors should not use poor security examples, schooling is supposed to carry over to work. It makes one wonder if the instructor is knowledgeable. – zaph Dec 24 '15 at 23:34
0

Since you're storing encrypted password and salt in your database, it would be easy for to you check the user's identity.

Algorithm:

  1. Fetch user's data using his/her email.

  2. Send user's raw input password, salt(selected from the database) and the original encrypted password(also selected from the database) to validateUser() function.

  3. In validateUser() function perform the same encryption again on user's raw input password and compare with user's original encrypted password.

Your code should be like this:

public function getUserByEmailAndPassword($email, $password) {

    $stmt = $this->conn->prepare("SELECT * FROM users WHERE email = ?");

    $stmt->bind_param("s", $email);

    if ($stmt->execute()) {
        $user = $stmt->get_result()->fetch_assoc();
        $stmt->close();
        if(validateUser($password, $user['salt'], $user['encrypted_password'])){
            return $user;
        }else{
            return false;
        }
    } else {
        return false;
    }
}


public function validateUser($raw_password, $salt, $original_encrypted_password) {
    $user_encrypted_password = base64_encode(sha1($raw_password . $salt, true) . $salt);
    if($user_encrypted_password == $original_encrypted_password){
        return true;
    }else{
        return false;
    }
}
Rajdeep Paul
  • 16,887
  • 3
  • 18
  • 37