Реализация функции хеширования MySQL
Я знаю, что php имеет функции md5(), sha1() и hash(), но я хочу создать хэш, используя функцию MySQL PASSWORD(). Пока что единственный способ, которым я могу думать, - просто запросить сервер, но мне нужна функция (желательно в php или Perl), которая будет делать то же самое без запроса MySQL вообще.
Например:
MySQL hash → 464bb2cb3cf18b66
MySQL5 hash → * 01D01F5CA7CA8BA771E03F4AC55EC73C11EFA229
Спасибо!
Ответы
Ответ 1
Первоначально я наткнулся на этот вопрос в своем собственном поиске 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
Надеюсь, кому-то это тоже пригодится :)
Ответ 2
Если вас интересует алгоритм этой функции, загрузите исходный код и посмотрите файл sql/password.c или отметьте this реализация.
Ответ 3
Да, слишком поздно, но я просто придумал эту реализацию на этой странице: 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);
}
Ответ 4
Почему вы хотите использовать функцию mysql password()?
Даже документация Mysql советует против этого:
http://dev.mysql.com/doc/refman/5.0/en/encryption-functions.html#function_password
Функция PASSWORD() используется системой аутентификации в MySQL Server; вы не должны использовать его в своих приложениях
Вы можете использовать md5(), например, который присутствует почти на каждом языке программирования, включая php и perl.
Ответ 5
На основе вышеприведенной реализации PHP здесь приведен пример Perl.
use Digest::SHA1 qw(sha1 sha1_hex);
sub password { "*".uc(sha1_hex(sha1($_[0]))) }
Функция пароля возвращает то же, что и функция MySQL5 PASSWORD().
В ответ на вопрос "зачем кому-то это нужно?" я использую его для создания операторов SQL "CREATE USER", которые не содержат паролей с открытым текстом.
Ответ 6
Плохие парни делают это в 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^^}"
OT, но в любом случае...:)
Ответ 7
Реализация 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);
}