15

I know that php has md5(), sha1(), and the hash() functions, but I want to create a hash using the MySQL PASSWORD() function. So far, the only way I can think of is to just query the server, but I want a function (preferably in php or Perl) that will do the same thing without querying MySQL at all.

For example:

MySQL hash -> 464bb2cb3cf18b66

MySQL5 hash -> *01D01F5CA7CA8BA771E03F4AC55EC73C11EFA229

Thanks!

6
  • I don't get it. You want to use the MySQL PASSWORD function, but in Perl/php? What's the point? Commented Nov 3, 2008 at 22:54
  • The point is that he probably wants to try hacking into a mysql server, and somehow got the dump of the hashcodes, so he's trying to use a password cracker to get the originals back. Commented Nov 3, 2008 at 23:35
  • 3
    Why does it matter what the point is? It's a straightforward question. I'd like to see an implementation of each of the MySQL password functions in PHP as well. Commented Oct 9, 2009 at 12:19
  • Added my PHP implementations :) Commented Oct 9, 2009 at 13:46
  • 1
    A real-world use case: I have to update an old database that used the MySQL hashing system. I'm migrating users to the PHP password hashing system, but checking the existing password would require a call to the database. This was turning my clean code into a nightmare of odd interfaces and spaghetti. Hashing the password in PHP is so much easier. Commented Sep 25, 2014 at 22:33

7 Answers 7

27

I originally stumbled across this question in my own search for a PHP implementation of the two MySQL password hashing functions. I was unable to find any implementations, so I adapted my own from the MySQL source code (sql/password.c). The following are tested and working in PHP 5.2:

// The following is free for any use provided credit is given where due.
// This code comes with NO WARRANTY of any kind, including any implied warranty.

/**
 * MySQL "OLD_PASSWORD()" AKA MySQL323 HASH FUNCTION
 * This is the password hashing function used in MySQL prior to version 4.1.1
 * By Defines Fineout 10/9/2009 9:12:16 AM
**/
function mysql_old_password_hash($input, $hex = true)
{
  $nr = 1345345333; $add = 7; $nr2 = 0x12345671; $tmp = null;
  $inlen = strlen($input);
  for ($i = 0; $i < $inlen; $i++) {
    $byte = substr($input, $i, 1);
    if ($byte == ' ' || $byte == "\t") continue;
    $tmp = ord($byte);
    $nr ^= ((($nr & 63) + $add) * $tmp) + (($nr << 8) & 0xFFFFFFFF);
    $nr2 += (($nr2 << 8) & 0xFFFFFFFF) ^ $nr;
    $add += $tmp;
  }
  $out_a = $nr & ((1 << 31) - 1);
  $out_b = $nr2 & ((1 << 31) - 1);
  $output = sprintf("%08x%08x", $out_a, $out_b);
  if ($hex) return $output;
  return hex_hash_to_bin($output);
} //END function mysql_old_password_hash

/**
 * MySQL "PASSWORD()" AKA MySQLSHA1 HASH FUNCTION
 * This is the password hashing function used in MySQL since version 4.1.1
 * By Defines Fineout 10/9/2009 9:36:20 AM
**/
function mysql_password_hash($input, $hex = true)
{
  $sha1_stage1 = sha1($input, true);
  $output = sha1($sha1_stage1, !$hex);
  return $output;
} //END function mysql_password_hash

/**
 * Computes each hexidecimal pair into the corresponding binary octet.
 * Similar to mysql hex2octet function.
**/
function hex_hash_to_bin($hex)
{
  $bin = "";
  $len = strlen($hex);
  for ($i = 0; $i < $len; $i += 2) {
    $byte_hex = substr($hex, $i, 2);
    $byte_dec = hexdec($byte_hex);
    $byte_char = chr($byte_dec);
    $bin .= $byte_char;
  }
  return $bin;
} //END function hex_hash_to_bin

Hopefully someone else will find this useful as well :)

Sign up to request clarification or add additional context in comments.

3 Comments

Works perfect! Nice php implementation.
I had some problems on an old linux server running PHP 5.1.6, tracked down the issue ((1 << 31) - 1) calculating to 0x80000000 instead of 0x7FFFFFFF. I didn't bother researching whether or not its a 5.1 bug or something else. Regardless, I replaced $out_a and $out_b assignments and worked like a charm. Thanks!
Yep it's a version-specific bug with integer overflow from what I can tell.
17

If you are interested in the algorithm of this function, download the source code and see the file sql/password.c, or check this implementation.

2 Comments

I don't know why you haven't been up-voted more, you're the only one in the thread who actually answered the guys question... go you!
Indeed. I too came here looking for the actual algorithm. It's not in the MySQL documentation. Thanks CMS.
5

Yes, too late but I just came up this implementation on that page: http://dev.mysql.com/doc/refman/5.1/en/password-hashing.html

Here is the equivalent php function to mysql password;

function mysql_41_password($in) {
    $p = sha1($in, true);
    $p = sha1($p);
    return '*'. strtoupper($p);
} 

Comments

4

Why do you want to use mysql password() function? Even the Mysql documentation advises against this:

http://dev.mysql.com/doc/refman/5.0/en/encryption-functions.html#function_password

The PASSWORD() function is used by the authentication system in MySQL Server; you should not use it in your own applications

You can use md5() for example, wich is present in almost every programming language, php and perl included.

3 Comments

MD5 has been broken. So has SHA1. NIST recommends using a SHA-2 family function such as SHA224, SHA256, SHA384 or SHA512. csrc.nist.gov/groups/ST/toolkit/secure_hashing.html
The thread starter just wanted to create a hash, and did not say he would use it for storing passwords, so I didn't mind about the strength of the md5 algorithm.
Why do you care what he wants the function for? He didn't say he was using it in an application, and specifically stated he didn't want to use MD5.
1

Based on the PHP implementation above, here's a Perl example that works.

use Digest::SHA1 qw(sha1 sha1_hex);
sub password { "*".uc(sha1_hex(sha1($_[0]))) }

The password function returns the same as the MySQL5 PASSWORD() function.

In answer to "why would anyone want to do this?", I use it to generate SQL "CREATE USER" statements that don't contain plain-text passwords.

Comments

1

Bad boys do that in bash with sha1sum ;)

PHRASE="password"; P1=`echo -n "${PHRASE}"|sha1sum`; P2="*`echo -en $(echo -n ${P1%% *}|sed -E 's/([0-9a-f]{2})/\\\x\1/g')|sha1sum -b`"; PASS="${P2%% *}"; echo "${PASS^^}"

OT, but anyway... :)

Comments

0

Perl 5 implementation of old_password() based on the PHP example.

sub old_hash_password {
    my ($password) = @_;

    my $nr = 1345345333;
    my $nr2 = 0x12345671;
    my $add = 7;

    for (my $i = 0; $i < length($password); $i++) {
        my $byte = substr($password, $i, 1);

        next if ($byte eq ' ' || $byte eq "\t");

        my $ord_b = ord($byte);
        $nr ^= ((($nr & 63) + $add) * $ord_b) + (($nr << 8) & 0xFFFFFFFF);
        $nr2 += (($nr2 << 8) & 0xFFFFFFFF) ^ $nr;
        $add += $ord_b;
    }

    my $out_a = $nr & ((1 << 31) - 1);
    my $out_b = $nr2 & ((1 << 31) - 1);

    return sprintf("%08x%08x", $out_a, $out_b);
}

Comments

Your Answer

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