Geoff
Geoff

Reputation: 197

sha1 in php not storing properly in mysql

I use the following code to store a password into mysql

    if (!$errors) {
    // include the connection file
    require_once('connection.inc.php');
    $conn = dbConnect('write');
    // create a salt using the current timestamp
    $salt = time();
    // encrypt the password and salt
    $pwd = sha1($password, $salt);
    echo $pwd;
    // prepare SQL statement
    $sql = 'INSERT INTO users (username, salt, pwd)
            VALUES (?, ?, ?)';
    $stmt = $conn->stmt_init();
    $stmt = $conn->prepare($sql);
    // bind parameters and insert the details into the database
    $stmt->bind_param('sis', $username, $salt, $pwd);
    $stmt->execute();
    if ($stmt->affected_rows == 1) {
        $success = "$username has been registered. You may now log in.";
    } elseif ($stmt->errno == 1062) {
        $errors[] = "$username is already in use. Please choose another username.";
        } else {
            $errors[] = 'Sorry, there was a problem with the database.';
        }

}

The password field, pwd, is defined as CHAR 40. When I examine it I see that it contains the following:

ƒ7Ž{9‰ù|EòsŒs”ºþ

no matter what password I enter. Naturally, this doesn't compare to the password when I try to login looking at it with this code:

    require_once('connection.inc.php');
$conn = dbConnect('read');
// get the username's details from the database
$sql = 'SELECT salt, pwd FROM users WHERE username = ?';
// initialize and prepare  statement
$stmt = $conn->stmt_init();
$stmt->prepare($sql);
// bind the input parameter
$stmt->bind_param('s', $username);
// bind the result, using a new variable for the password
$stmt->bind_result($salt, $storedPwd);
$stmt->execute();
$stmt->fetch();
// encrypt the submitted password with the salt
// and compare with stored password
if (sha1($password . $salt) == $storedPwd) {
    $_SESSION['authenticated'] = 'Jethro Tull';
    // get the time the session started
    $_SESSION['start'] = time();
    session_regenerate_id();
    header("Location: $redirect");
    exit;
} else {
    // if no match, prepare error message
    echo "  pwd " . $password;
    echo "  salt " . $salt;
    echo "  sha1 " . sha1($password . $salt);
    echo "  St. pwd " . $storedPwd;
    $error = 'Invalid username or password';
}

Does anyone know why this is happening?

Upvotes: 2

Views: 1617

Answers (3)

Erik
Erik

Reputation: 2264

Not sure if this is your only problem but

 $pwd = sha1($password, $salt);

is not how you use the sha1 function. http://php.net/manual/en/function.sha1.php

time() will always evaluate to TRUE and thus you're inserting a raw binary format into your char password field. Causing the issue that you're seeing.

What you probably want to do is

 $pwd = sha1($password . $salt);
                       ^

Upvotes: 3

Filip Roséen
Filip Roséen

Reputation: 63807

You have a simple typo where you have written a comma (,) instead of a dot (.) when inserting your data to your database.

// encrypt the password and salt
$pwd = sha1($password, $salt);

Compare this to where you generate the hashsum when validating your password:

// encrypt the submitted password with the salt
// and compare with stored password
if (sha1($password . $salt) == $storedPwd) {

Since the two have very different meanings a mistake that small will have huge consequences overall.

You wanted to form a new string consisting of $password plus $salt but instead you are now giving sha1 two arguments instead of one.

The second argument to sha1 controls what kind of data the function will return, plaintext (if false, default) vs raw data (if true).

Upvotes: 0

Marc B
Marc B

Reputation: 360702

sha1 returns the binary hash by default, which you're storing in a char field - char fields are subject to charset translation, which means mysql is mangling the hash. Convert the field to a binary/varbinary instead, which are NOT subject to charset translation

Upvotes: 0

Related Questions