Алгоритм MD5 в PHP - не работает
Чтобы получить опыт, я хочу построить алгоритм MD5 на PHP. Я прочитал RFC 1321 и собрал свой код, как в описании, но я не получаю то же значение хеша, что и в оригинальной функции md5.
<?php //https://tools.ietf.org/html/rfc1321
include_once "md5_util.php";
$in = "Hello, World!";
echo "Input: <strong>".$in."</strong><br>";
$hash = "";
$b = ""; //Binary string of input
for($i = 0; $i < strlen($in); $i++){
$byte = decbin(ord(substr($in, $i, 1)));
while(strlen($byte) < 8){ //pad 0's before the byte string while it's length isn't 8
$byte = "0".$byte;
}
$b .= $byte;
}
$b_original = $b; //original binary string
/*
MD5
*/
//1.1 appedn "1"
$b .= "1";
//1.2 pad with "0" until length is 64 bit smaller than a multiple of 512
while(strlen($b) % 512 != 448){
$b .= "0";
}
//2.1 Append the bit length of input stream in 64 bits
$len_bin = decbin(strlen($b_original));
if(strlen($len_bin) < 64){
while(strlen($len_bin) < 64){
$len_bin = "0" . $len_bin;
}
}else if(strlen($len_bin) > 64){
while(strlen($len_bin) > 64){
$len_bin = substr($len_bin, 1);
}
}
$len_bin_low = substr($len_bin, 32);
$len_bin_high = substr($len_bin, 0, 32);
$b .= $len_bin_low . $len_bin_high;
$M = array();
$N = strlen($b) / 32; //Number of 32-bit-words, must be a multiple of 16
for($i = 0; $i < $N; $i++){
$M[$i] = substr($b, $i * 32, 32);
}
//3. Words (Hex=>Decimal)
$a = hexdec("67452301");
$b = hexdec("efcdab89");
$c = hexdec("98badcfe");
$d = hexdec("10325476");
//4.1 Functions (take decimal values, reurn deciaml values)
function F($x, $y, $z){
// (X AND Y) OR ((NOT X) AND Z
return (($x & $y) | ((~$x) & $z));
}
function G($x, $y, $z){
// (X AND Z) OR (Y AND (NOT Z)
return (($x & $z) | ($y & (~$z)));
}
function H($x, $y, $z){
// X XOR Y XOR Z
return ($x ^ $y ^ $z);
}
function I($x, $y, $z){
// Y XOR (X OR (NOT Z))
return ($y ^ ($x | (~$z)));
}
//4.2 Table of 1-64 elements, each element i is integer part of (abs(sin(i)) * 4294967296)
$T = array();
for($i = 1; $i <= 64; $i++){
$T[$i] = hexdec(dechex(intval(abs(sin($i)) * 4294967296)));
//hexdec(dechex()) to eleminate signs
}
//4.3 subdivide in 32-bit-words
for($i = 0; $i <= ($N/16) - 1; $i++){
$X = array();
for($j = 0; $j <= 15; $j++){
$X[$j] = $M[($i*16)+$j];
}
$AA = $a;
$BB = $b;
$CC = $c;
$DD = $d;
//Round 1 (all valeus are decimal)
R1($a, $b, $c, $d, 0, 7, 1);
R1($d, $a, $b, $c, 1, 12, 2);
R1($c, $d, $a, $b, 2, 17, 3);
R1($b, $c, $d, $a, 3, 22, 4);
R1($a, $b, $c, $d, 4, 7, 5);
R1($d, $a, $b, $c, 5, 12, 6);
R1($c, $d, $a, $b, 6, 17, 7);
R1($b, $c, $d, $a, 7, 22, 8);
R1($a, $b, $c, $d, 8, 7, 9);
R1($d, $a, $b, $c, 9, 12, 10);
R1($c, $d, $a, $b, 10, 17, 11);
R1($b, $c, $d, $a, 11, 22, 12);
R1($a, $b, $c, $d, 12, 7, 13);
R1($d, $a, $b, $c, 13, 12, 14);
R1($c, $d, $a, $b, 14, 17, 15);
R1($b, $c, $d, $a, 15, 22, 16);
//Round 2
R2($a, $b, $c, $d, 1, 5, 17);
R2($d, $a, $b, $c, 6, 9, 18);
R2($c, $d, $a, $b, 11, 14, 19);
R2($b, $c, $d, $a, 0, 20, 20);
R2($a, $b, $c, $d, 5, 5, 21);
R2($d, $a, $b, $c, 10, 9, 22);
R2($c, $d, $a, $b, 15, 14, 23);
R2($b, $c, $d, $a, 4, 20, 24);
R2($a, $b, $c, $d, 9, 5, 25);
R2($d, $a, $b, $c, 14, 9, 26);
R2($c, $d, $a, $b, 3, 14, 27);
R2($b, $c, $d, $a, 8, 20, 28);
R2($a, $b, $c, $d, 13, 5, 29);
R2($d, $a, $b, $c, 2, 9, 30);
R2($c, $d, $a, $b, 7, 14, 31);
R2($b, $c, $d, $a, 12, 20, 32);
//Round 3
R3($a, $b, $c, $d, 5, 4, 33);
R3($d, $a, $b, $c, 8, 11, 34);
R3($c, $d, $a, $b, 11, 16, 35);
R3($b, $c, $d, $a, 14, 23, 36);
R3($a, $b, $c, $d, 1, 4, 37);
R3($d, $a, $b, $c, 4, 11, 38);
R3($c, $d, $a, $b, 7, 16, 39);
R3($b, $c, $d, $a, 10, 23, 40);
R3($a, $b, $c, $d, 13, 4, 41);
R3($d, $a, $b, $c, 0, 11, 42);
R3($c, $d, $a, $b, 3, 16, 43);
R3($b, $c, $d, $a, 6, 23, 44);
R3($a, $b, $c, $d, 9, 4, 45);
R3($d, $a, $b, $c, 12, 11, 46);
R3($c, $d, $a, $b, 15, 16, 47);
R3($b, $c, $d, $a, 2, 23, 48);
//Round 4
R4($a, $b, $c, $d, 0, 6, 49);
R4($d, $a, $b, $c, 7, 10, 50);
R4($c, $d, $a, $b, 14, 15, 51);
R4($b, $c, $d, $a, 5, 21, 52);
R4($a, $b, $c, $d, 12, 6, 53);
R4($d, $a, $b, $c, 3, 10, 54);
R4($c, $d, $a, $b, 10, 15, 55);
R4($b, $c, $d, $a, 1, 21, 56);
R4($a, $b, $c, $d, 8, 6, 57);
R4($d, $a, $b, $c, 15, 10, 58);
R4($c, $d, $a, $b, 6, 15, 59);
R4($b, $c, $d, $a, 13, 21, 60);
R4($a, $b, $c, $d, 4, 6, 61);
R4($d, $a, $b, $c, 11, 10, 62);
R4($c, $d, $a, $b, 2, 15, 63);
R4($b, $c, $d, $a, 9, 21, 64);
$a = $a + $AA;
$b = $b + $BB;
$c = $c + $CC;
$d = $d + $DD;
}
//decimal variables to binary
$a = appendZeroAtBegin(decbin($a), 32);
$b = appendZeroAtBegin(decbin($b), 32);
$c = appendZeroAtBegin(decbin($c), 32);
$d = appendZeroAtBegin(decbin($d), 32);
echo "A: ".binhex($a)."<br>";
echo "B: ".binhex($b)."<br>";
echo "C: ".binhex($c)."<br>";
echo "D: ".binhex($d)."<br>";
$a_b = array_reverse(splitIntoBytes($a));
$b_b = array_reverse(splitIntoBytes($b));
$c_b = array_reverse(splitIntoBytes($c));
$d_b = array_reverse(splitIntoBytes($d));
$hash = implode("", $a_b).implode("", $b_b).implode("", $c_b).implode("", $d_b);
echo "Hash value: <strong>" . binhex($hash) . "</strong><br>Original MD5: <strong>" . md5($in) . "</strong><br>";
md5_util.php:
<?php
function hexbin($str){
$hexbinmap = array(
"0" => "0000",
"1" => "0001",
"2" => "0010",
"3" => "0011",
"4" => "0100",
"5" => "0101",
"6" => "0110",
"7" => "0111",
"8" => "1000",
"9" => "1001",
"a" => "1010",
"b" => "1011",
"c" => "1100",
"d" => "1101",
"e" => "1110",
"f" => "1111");
$bin = "";
for ($i = 0; $i < strlen($str); $i++)
{
$bin .= $hexbinmap[strtolower($str[$i])];
}
//$bin = ltrim($bin, '0');
return $bin;
}
function binhex($str){
$binhexmap = array(
"0000" => "0",
"0001" => "1",
"0010" => "2",
"0011" => "3",
"0100" => "4",
"0101" => "5",
"0110" => "6",
"0111" => "7",
"1000" => "8",
"1001" => "9",
"1010" => "a",
"1011" => "b",
"1100" => "c",
"1101" => "d",
"1110" => "e",
"1111" => "f");
$hex = "";
foreach(explode("\r\n", chunk_split($str, 4)) as $ch){
if(empty($ch)) continue;
$hex .= $binhexmap[$ch];
}
return $hex;
}
function rotateLeft($exp, $s){
//decimal parameters and returns
$exp_bin = decbin($exp);
$new_exp = "";
for($i = $s; $i < strlen($exp_bin); $i++){
$new_exp .= substr($exp_bin, $i, 1);
}
for($i = 0; $i < $s; $i++){
$new_exp .= substr($exp_bin, $i, 1);
//$new_exp .= "0";
}
return bindec($new_exp);
//return (($exp << $s) | ($exp >> (32 - $s)));
}
function appendZeroAtBegin($bin, $len){
$new_bin = $bin;
while(strlen($new_bin) < $len){
$new_bin = "0" . $new_bin;
}
return $new_bin;
}
function splitIntoBytes($bin){
//returns high order bits first;
$arr = array();
if(strlen($bin) % 8 != 0) return $bin;
for($i = 0; $i < strlen($bin) / 4; $i++){
$arr[] = substr($bin, $i * 8, 8);
}
return $arr;
}
function R1(&$a, $b, $c, $d, $k, $s, $i){
global $X, $T;
/* $a = rotateLeft(($a + F($b, $c, $d) + $X[$k] + $T[$i]), $s) + $b;*/
$a = F($b, $c, $d) + $X[$k] + $T[$i];
$a = rotateLeft($a, $s);
$a += $b;
}
function R2(&$a, $b, $c, $d, $k, $s, $i){
global $X, $T;
/* $a = rotateLeft(($a + G($b, $c, $d) + $X[$k] + $T[$i]), $s) + $b;*/
$a = G($b, $c, $d) + $X[$k] + $T[$i];
$a = rotateLeft($a, $s);
$a += $b;
}
function R3(&$a, $b, $c, $d, $k, $s, $i){
global $X, $T;
/* $a = rotateLeft(($a + H($b, $c, $d) + $X[$k] + $T[$i]), $s) + $b;*/
$a = H($b, $c, $d) + $X[$k] + $T[$i];
$a = rotateLeft($a, $s);
$a += $b;
}
function R4(&$a, $b, $c, $d, $k, $s, $i){
global $X, $T;
/* $a = rotateLeft(($a + I($b, $c, $d) + $X[$k] + $T[$i]), $s) + $b;*/
$a = I($b, $c, $d) + $X[$k] + $T[$i];
$a = rotateLeft($a, $s);
$a += $b;
}
Я знаю, что есть еще один вопрос по этой теме (и я тоже читал), но я хочу знать, где в моем коде ошибка:)
Спасибо