4

I am working with site that is done with WordPress, and I need to add some parts that are outside WP, and to check user login, Logging users outside WP.

I tried with md5 of password but it's not...

I tried this code:

require_once( 'wp-includes/class-phpass.php' );
$wp_hasher = new PasswordHash( 8, TRUE );
$password = "passwordhere";
$hashed_password = $wp_hasher->HashPassword( $password );
$encryptedpass = md5($hashed_password);

But this is only for first time creating password, and it's always different.

I need code that can be used in this:

SELECT * FROM wp_customers WHERE email = "[email protected]" AND password = "<what goes here?>"

Is this possible anyhow?

Thanks.

4 Answers 4

7

Based on your other question ... it sounds like you're trying to validate a given plaintext password against what's stored in the database. Here's the function WordPress uses to do just that:

function wp_check_password($password, $hash, $user_id = '') {
    global $wp_hasher;

    // If the hash is still md5...
    if ( strlen($hash) <= 32 ) {
        $check = ( $hash == md5($password) );
        if ( $check && $user_id ) {
            // Rehash using new hash.
            wp_set_password($password, $user_id);
            $hash = wp_hash_password($password);
        }

        return apply_filters('check_password', $check, $password, $hash, $user_id);
    }

    // If the stored hash is longer than an MD5, presume the
    // new style phpass portable hash.
    if ( empty($wp_hasher) ) {
        require_once ( ABSPATH . 'wp-includes/class-phpass.php');
        // By default, use the portable hash from phpass
        $wp_hasher = new PasswordHash(8, TRUE);
    }

    $check = $wp_hasher->CheckPassword($password, $hash);

    return apply_filters('check_password', $check, $password, $hash, $user_id);
}

First, this plugin checks to see if the MD5 hash of the given password is the same as the stored (hashed) password for a user. It also checks to see if the PHPass hash of the given password is the same as the stored password for a user.

You can follow a similar pattern.

So let's say you're given a username and a password from the user and you want to validate them (my_password_validation( $username, $password )). You'll use the given username to pull a hashed password from the database. Then you compare the hash of the given password to the stored value to see if it's valid.

Here's some untested psuedocode:

function my_password_validation( $username, $password ) {
    // Select the users's password hash from the database
    $stored = query( 'SELECT * FROM wp_customers WHERE email = ' . $username );

    require_one( 'class-phpass.php' );
    $hasher = new PasswordHash(8, TRUE);

    return $hasher->CheckPassword( $password, $stored );
}

If the password you pass in to the function hashes to the same as the stored value, the function will return true. Otherwise it will return false.

Looking at the comments you left on the other question, it seems like you have some other issues, though. To quote:

So I get:

$P$BqVYujC/jqNY4aylZpHi475jwcaSUs1 But how can I compare that with one in DB?

One in DB is:

fa063a4ed35e092a2d4e15c1b6a61871 How to compare those two with MySQL?

I can tell you right now that the password you're getting from the database was not hashed using the PHPass utility. Those hashes will always resemble the $P$B starting because that's what tells the system how it was hashed. PHPass is based on Blowfish which uses that kind of a prefix on encrypted strings.

Your fa063... hash looks more like a standard MD5 hash ... so if your MD5 hash of the plaintext doesn't match, then I think you might have the wrong password.

To answer your "how to I compare those two with MySQL" question ... you don't. MySQL is the data store ... don't do any business logic or comparison in the data store. Read data out, then use a PHP script to perform your comparison.

2
  • 1
    These "MySQL is the data store...don't do any business logic or comparisons in the data store" are a little overblown, honestly. Database servers are powerful tools. They most definitely are not "just" data stores and they've been getting short shrift the past few years to everyone's detriment, IMO. Jun 16, 2015 at 23:35
  • In the wordpress database, there is a user table, and in that table is a user_pass field. Is that the "stored" hash that you send as the second parameter to the function $hasher->CheckPassword() ?
    – Millar248
    Apr 11, 2021 at 5:34
5

It's very easy..

<?php
include_once($_SERVER['DOCUMENT_ROOT'].'/wp-includes/class-phpass.php' );

// prepare database connection
$ip_address="localhost";
$user_db="userdb";
$pass_db="passdb";

$conn= mysql_connect($ip_address,$user_db,$pass_db);
mysql_select_db("dbname",$conn);
if (!$conn){
            echo "Could not connect: " . mysql_error();
            exit();
}

// wordpress' username that his password going to compare
$user = 'test';
$user_name = htmlspecialchars($user,ENT_QUOTES);

// plain password to compare
$password = 'tespass';

$hasher = new PasswordHash(8, TRUE);

// get user_name's hashed password from wordpress database
$queryx = "select * from wa1gty5f_users where user_login='$user_name'";
$Resultx = mysql_query($queryx,$conn);

while($row = mysql_fetch_array($Resultx)){
     $passnya = $row[user_pass];
}

// compare plain password with hashed password
if ($hasher->CheckPassword( $password, $passnya )){
    echo "MATCHED";
} else {
    echo "NO MATCHED";
}
?>
3
  • 1
    PasswordHash is not a core php class, so if you don't include it, you get an error. Remember that user asked to validate password outside WordPress, so WP classes and functions are not available.
    – gmazzap
    Sep 25, 2013 at 4:56
  • 1
    @ialocin it's a WordPress core class, not a PHP core class.
    – gmazzap
    Jul 10, 2015 at 10:54
  • My bad! Should have read more thoroughly.. @gmazzap Jul 10, 2015 at 10:56
1

I had this problem and found out right on wp_hash_password()

Compare an already hashed password with its plain-text string

<?php

$wp_hasher = new PasswordHash(8, TRUE);

$password_hashed = '$P$B55D6LjfHDkINU5wF.v2BuuzO0/XPk/';
$plain_password = 'test';

if($wp_hasher->CheckPassword($plain_password, $password_hashed)) {
    echo "YES, Matched";
} else {
    echo "No, Wrong Password";
}

?>
0

Finally, almost 10 years later. Found exact answer, what question is looking for.

You want do it with using Core PHP, right? Here is the code for you! First you need to add a class: -> just copy it from wp-includes/class-phpass.php -> don't worry. its written in core PHP.

class PasswordHash {
    var $itoa64;
    var $iteration_count_log2;
    var $portable_hashes;
    var $random_state;

    /**
     * PHP5 constructor.
     */
    function __construct( $iteration_count_log2, $portable_hashes )
    {
        $this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';

        if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
            $iteration_count_log2 = 8;
        $this->iteration_count_log2 = $iteration_count_log2;

        $this->portable_hashes = $portable_hashes;

        $this->random_state = microtime() . uniqid(rand(), TRUE); // removed getmypid() for compatibility reasons
    }

    /**
     * PHP4 constructor.
     */
    public function PasswordHash( $iteration_count_log2, $portable_hashes ) {
        self::__construct( $iteration_count_log2, $portable_hashes );
    }

    function get_random_bytes($count)
    {
        $output = '';
        if ( @is_readable('/dev/urandom') &&
            ($fh = @fopen('/dev/urandom', 'rb'))) {
            $output = fread($fh, $count);
            fclose($fh);
        }

        if (strlen($output) < $count) {
            $output = '';
            for ($i = 0; $i < $count; $i += 16) {
                $this->random_state =
                    md5(microtime() . $this->random_state);
                $output .=
                    pack('H*', md5($this->random_state));
            }
            $output = substr($output, 0, $count);
        }

        return $output;
    }

    function encode64($input, $count)
    {
        $output = '';
        $i = 0;
        do {
            $value = ord($input[$i++]);
            $output .= $this->itoa64[$value & 0x3f];
            if ($i < $count)
                $value |= ord($input[$i]) << 8;
            $output .= $this->itoa64[($value >> 6) & 0x3f];
            if ($i++ >= $count)
                break;
            if ($i < $count)
                $value |= ord($input[$i]) << 16;
            $output .= $this->itoa64[($value >> 12) & 0x3f];
            if ($i++ >= $count)
                break;
            $output .= $this->itoa64[($value >> 18) & 0x3f];
        } while ($i < $count);

        return $output;
    }

    function gensalt_private($input)
    {
        $output = '$P$';
        $output .= $this->itoa64[min($this->iteration_count_log2 +
            ((PHP_VERSION >= '5') ? 5 : 3), 30)];
        $output .= $this->encode64($input, 6);

        return $output;
    }

    function crypt_private($password, $setting)
    {
        $output = '*0';
        if (substr($setting, 0, 2) == $output)
            $output = '*1';

        $id = substr($setting, 0, 3);
        # We use "$P$", phpBB3 uses "$H$" for the same thing
        if ($id != '$P$' && $id != '$H$')
            return $output;

        $count_log2 = strpos($this->itoa64, $setting[3]);
        if ($count_log2 < 7 || $count_log2 > 30)
            return $output;

        $count = 1 << $count_log2;

        $salt = substr($setting, 4, 8);
        if (strlen($salt) != 8)
            return $output;

        # We're kind of forced to use MD5 here since it's the only
        # cryptographic primitive available in all versions of PHP
        # currently in use.  To implement our own low-level crypto
        # in PHP would result in much worse performance and
        # consequently in lower iteration counts and hashes that are
        # quicker to crack (by non-PHP code).
        if (PHP_VERSION >= '5') {
            $hash = md5($salt . $password, TRUE);
            do {
                $hash = md5($hash . $password, TRUE);
            } while (--$count);
        } else {
            $hash = pack('H*', md5($salt . $password));
            do {
                $hash = pack('H*', md5($hash . $password));
            } while (--$count);
        }

        $output = substr($setting, 0, 12);
        $output .= $this->encode64($hash, 16);

        return $output;
    }

    function gensalt_extended($input)
    {
        $count_log2 = min($this->iteration_count_log2 + 8, 24);
        # This should be odd to not reveal weak DES keys, and the
        # maximum valid value is (2**24 - 1) which is odd anyway.
        $count = (1 << $count_log2) - 1;

        $output = '_';
        $output .= $this->itoa64[$count & 0x3f];
        $output .= $this->itoa64[($count >> 6) & 0x3f];
        $output .= $this->itoa64[($count >> 12) & 0x3f];
        $output .= $this->itoa64[($count >> 18) & 0x3f];

        $output .= $this->encode64($input, 3);

        return $output;
    }

    function gensalt_blowfish($input)
    {
        # This one needs to use a different order of characters and a
        # different encoding scheme from the one in encode64() above.
        # We care because the last character in our encoded string will
        # only represent 2 bits.  While two known implementations of
        # bcrypt will happily accept and correct a salt string which
        # has the 4 unused bits set to non-zero, we do not want to take
        # chances and we also do not want to waste an additional byte
        # of entropy.
        $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

        $output = '$2a$';
        $output .= chr(ord('0') + $this->iteration_count_log2 / 10);
        $output .= chr(ord('0') + $this->iteration_count_log2 % 10);
        $output .= '$';

        $i = 0;
        do {
            $c1 = ord($input[$i++]);
            $output .= $itoa64[$c1 >> 2];
            $c1 = ($c1 & 0x03) << 4;
            if ($i >= 16) {
                $output .= $itoa64[$c1];
                break;
            }

            $c2 = ord($input[$i++]);
            $c1 |= $c2 >> 4;
            $output .= $itoa64[$c1];
            $c1 = ($c2 & 0x0f) << 2;

            $c2 = ord($input[$i++]);
            $c1 |= $c2 >> 6;
            $output .= $itoa64[$c1];
            $output .= $itoa64[$c2 & 0x3f];
        } while (1);

        return $output;
    }

    function HashPassword($password)
    {
        if ( strlen( $password ) > 4096 ) {
            return '*';
        }

        $random = '';

        if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) {
            $random = $this->get_random_bytes(16);
            $hash =
                crypt($password, $this->gensalt_blowfish($random));
            if (strlen($hash) == 60)
                return $hash;
        }

        if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) {
            if (strlen($random) < 3)
                $random = $this->get_random_bytes(3);
            $hash =
                crypt($password, $this->gensalt_extended($random));
            if (strlen($hash) == 20)
                return $hash;
        }

        if (strlen($random) < 6)
            $random = $this->get_random_bytes(6);
        $hash =
            $this->crypt_private($password,
            $this->gensalt_private($random));
        if (strlen($hash) == 34)
            return $hash;

        # Returning '*' on error is safe here, but would _not_ be safe
        # in a crypt(3)-like function used _both_ for generating new
        # hashes and for validating passwords against existing hashes.
        return '*';
    }

    function CheckPassword($password, $stored_hash)
    {
        if ( strlen( $password ) > 4096 ) {
            return false;
        }

        $hash = $this->crypt_private($password, $stored_hash);
        if ($hash[0] == '*')
            $hash = crypt($password, $stored_hash);

        return $hash === $stored_hash;
    }
}

You are almost done.

$password = 'binary1001';//password you want to verify

$hasher = new PasswordHash(8, TRUE);
$passnya = '$P$BFG8I1k171qgRKqZvj0K3tn3bBSrsW/';//hash of that password from wp db


// compare plain password with hashed password
if ($hasher->CheckPassword( $password, $passnya )){
    echo "MATCHED";
} else {
    echo "NO MATCHED";
}

I made it here with trial and error. Now, its time for you to get to the point. Happy coding!!!

2
  • But that's just BagusS's answer with the database access edited out, isn't it? And even that's just essentially the bit of EAMann's answer that's marked 'untested pseudocode', which was posted ten years ago.
    – Rup
    Mar 28, 2021 at 21:54
  • yes! you are right! I just wanted to show that its actually working and the full answer in one go! Mar 30, 2021 at 2:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.