Реализация функции хеширования MySQL

Я знаю, что в php есть функции md5(), sha1() и hash(), но я хочу создать хэш с помощью функции MySQL PASSWORD(). Пока что единственный способ, который я могу придумать, - это просто запросить сервер, но мне нужна функция (желательно на php или Perl), которая будет делать то же самое, вообще не запрашивая MySQL.

Например:

Хэш MySQL -> 464bb2cb3cf18b66

Хэш MySQL5 -> * 01D01F5CA7CA8BA771E03F4AC55EC73C11EFA229

Спасибо!


person Community    schedule 03.11.2008    source источник
comment
Я не понимаю. Вы хотите использовать функцию MySQL PASSWORD, но в Perl/php? В чем смысл?   -  person JesperE    schedule 04.11.2008
comment
Дело в том, что он, вероятно, хочет попробовать взломать сервер mysql и каким-то образом получил дамп хэш-кодов, поэтому он пытается использовать взломщик паролей, чтобы вернуть оригиналы.   -  person Zak    schedule 04.11.2008
comment
Почему важно, в чем суть? Это простой вопрос. Я хотел бы также увидеть реализацию каждой из функций пароля MySQL в PHP.   -  person defines    schedule 09.10.2009
comment
Добавлены мои реализации PHP :)   -  person defines    schedule 09.10.2009
comment
Реальный пример использования: мне нужно обновить старую базу данных, в которой использовалась система хеширования MySQL. Я перевожу пользователей на систему хеширования паролей PHP, но для проверки существующего пароля потребуется вызов базы данных. Это превращало мой чистый код в кошмар со странными интерфейсами и спагетти. Хешировать пароль в PHP намного проще.   -  person    schedule 26.09.2014
comment
Определенно только используйте mysql323 для временной миграции. Хэш-формат mysql323 крайне неустойчив к атакам грубой силы в автономном режиме. По состоянию на август 2016 года это хеш, с которым hashcat может работать быстрее всего — его легче взломать, чем даже NTLM или MD4!   -  person Royce Williams    schedule 08.08.2016


Ответы (7)


Первоначально я наткнулся на этот вопрос в своем собственном поиске PHP-реализации двух функций хеширования паролей MySQL. Мне не удалось найти никаких реализаций, поэтому я адаптировал свою из исходного кода MySQL (sql/password.c). Следующее протестировано и работает в 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

Надеюсь, кому-то это тоже будет полезно :)

person defines    schedule 09.10.2009
comment
Работает идеально! Хорошая реализация php. - person x2.; 21.10.2009
comment
У меня были некоторые проблемы на старом Linux-сервере с PHP 5.1.6, я отследил проблему ((1 ‹‹ 31) - 1), вычисляя 0x80000000 вместо 0x7FFFFFFFF. Я не удосужился выяснить, является ли это ошибкой 5.1 или чем-то еще. Несмотря на это, я заменил назначения $out_a и $out_b и работал как шарм. Спасибо! - person Pete; 30.07.2011
comment
Да, это ошибка конкретной версии с целочисленным переполнением, насколько я могу судить. - person defines; 01.08.2011

Если вас интересует алгоритм работы этой функции, скачайте исходный код и посмотрите файл sql/password.c, или проверьте эта реализация.

person Christian C. Salvadó    schedule 03.11.2008
comment
Я не знаю, почему за вас не проголосовали больше, вы единственный в треде, кто действительно ответил на вопрос ребят ... вперед! - person Keith Palmer Jr.; 07.10.2009
comment
Конечно. Я тоже пришел сюда в поисках фактического алгоритма. Это не в документации MySQL. Спасибо КМС. - person Omniwombat; 01.05.2010

Да, слишком поздно, но я только что нашел эту реализацию на этой странице: http://dev.mysql.com/doc/refman/5.1/en/password-hashing.html

Вот эквивалентная функция php для пароля mysql;

function mysql_41_password($in) {
    $p = sha1($in, true);
    $p = sha1($p);
    return '*'. strtoupper($p);
} 
person K-Gun    schedule 26.12.2011

Почему вы хотите использовать функцию mysql password()? Даже документация Mysql советует против этого:

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

Функция PASSWORD() используется системой аутентификации в MySQL Server; вы не должны использовать его в своих собственных приложениях

Например, вы можете использовать md5(), который присутствует почти во всех языках программирования, включая php и perl.

person Davide Gualano    schedule 03.11.2008
comment
MD5 был сломан. Так же как и SHA1. NIST рекомендует использовать функцию семейства SHA-2, такую ​​как SHA224, SHA256, SHA384 или SHA512. csrc.nist.gov/groups/ST/toolkit/secure_hashing.html - person jakber; 04.11.2008
comment
Автор темы просто хотел создать хэш и не говорил, что будет использовать его для хранения паролей, так что я не возражал против силы алгоритма md5. - person Davide Gualano; 04.11.2008
comment
Почему вас волнует, для чего ему нужна эта функция? Он не сказал, что использует его в приложении, и конкретно заявил, что не хочет использовать MD5. - person Keith Palmer Jr.; 07.10.2009

Основываясь на приведенной выше реализации PHP, вот работающий пример Perl.

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

Функция пароля возвращает то же самое, что и функция MySQL5 PASSWORD().

В ответ на вопрос «зачем кому-то это делать?», я использую его для создания операторов SQL «CREATE USER», которые не содержат паролей в виде простого текста.

person TFBW    schedule 07.04.2011

Плохие парни делают это в bash с 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^^}"

ОТ, но тем не менее... :)

person Community    schedule 09.02.2012

Реализация функции old_password() в Perl 5 на примере PHP.

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);
}
person Matthew Lenz    schedule 22.03.2018