Алгоритм 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;
}

Я знаю, что есть еще один вопрос по этой теме (и я тоже читал), но я хочу знать, где в моем коде ошибка:)

Спасибо

0 ответов

Другие вопросы по тегам