I am trying to write a PHP script that implements the MD5 algorithm just so that I can better understand MD5's inner-workings. For those of you already familiar with how MD5 works, could you help me figure out why my script is not producing the correct output?
<?php
$string = "";
$a = "01100111010001010010001100000001"; // 0x67452301
$b = "11101111110011011010101110001001"; // 0xEFCDAB89
$c = "10011000101110101101110011111110"; // 0x98BADCFE
$d = "00010000001100100101010001110110"; // 0x10325476
$aa = $a;
$bb = $b;
$cc = $c;
$dd = $d;
// PADDED BINARY FOR NULL STRING, I.E.: ""
$binary_md5 = "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
$binary_md5_words = strlen($binary_md5) / 32;
// SPLIT BINARY INTO 16 32-BIT WORDS
for($i = 1; $i <= $binary_md5_words; $i++) {
$m[] = substr($binary_md5, ($i - 1) * 32, 32);
}
// GENERATE T-VALUES
for($i = 0; $i < 64; $i++) {
$T[] = Pad(decbin(floor(4294967296 * abs(sin($i+1)))), 32);
}
/*
// PRINT THE M[K] ARRAY
echo "<h1>m[k] Array</h1><br>";
print_r($m);
echo "<br><br>";
// PRINT THE T[t] ARRAY
echo "<h1>T[t] Array</h1><br>";
print_r($T);
echo "<br><br>";
// TEST ANDxy
echo "<h1>Test ANDxy</h1><br>";
echo "$m[0]<br>$T[0]<br>";
echo ANDxy($m[0], $T[0]);
echo "<br><br>";
// TEST ORxy
echo "<h1>Test ORxy</h1><br>";
echo "$m[0]<br>$T[0]<br>";
echo ORxy($m[0], $T[0]);
echo "<br><br>";
// TEST ADDxy
echo "<h1>Test ADDxy</h1><br>";
echo "$m[0]<br>$T[0]<br>";
echo ADDxy($m[0], $T[0]);
echo "<br><br>";
// TEST XORxy
echo "<h1>Test XORxy</h1><br>";
echo "$m[0]<br>$T[0]<br>";
echo XORxy($m[0], $T[0]);
echo "<br><br>";
// TEST NOTx
echo "<h1>Test NOTx</h1><br>";
echo "$m[0]<br>";
echo NOTx($m[0]);
echo "<br><br>";
// TEST SHIFTleft
echo "<h1>Test SHIFTleft</h1><br>";
echo "$m[0]<br>";
echo SHIFTleft($m[0], 1);
echo "<br><br>";
// TEST F
echo "<h1>Test F</h1><br>";
echo "X = $m[0]<br>Y = $m[1]<br>Z = $m[2]<br>F = ";
echo F($m[0], $m[1], $m[2]);
$step1 = ANDxy($m[0], $m[1]);
$step2 = ANDxy(NOTx($m[0]), $m[2]);
$step3 = ORxy($step1, $step2);
echo "<br>F = $step3";
echo "<br><br>";
// TEST H
echo "<h1>Test H</h1><br>";
echo "X = $m[0]<br>Y = $m[1]<br>Z = $m[2]<br>F = ";
echo H($m[0], $m[1], $m[2]);
echo "<br><br>";
*/
// ROUND 1
$a = ff($a, $b, $c, $d, $m, 0, 7, $T[0]);
$d = ff($d, $a, $b, $c, $m, 1, 12, $T[1]);
$c = ff($c, $d, $a, $b, $m, 2, 17, $T[2]);
$b = ff($b, $c, $d, $a, $m, 3, 22, $T[3]);
$a = ff($a, $b, $c, $d, $m, 4, 7, $T[4]);
$d = ff($d, $a, $b, $c, $m, 5, 12, $T[5]);
$c = ff($c, $d, $a, $b, $m, 6, 17, $T[6]);
$b = ff($b, $c, $d, $a, $m, 7, 22, $T[7]);
$a = ff($a, $b, $c, $d, $m, 8, 7, $T[8]);
$d = ff($d, $a, $b, $c, $m, 9, 12, $T[9]);
$c = ff($c, $d, $a, $b, $m, 10, 17, $T[10]);
$b = ff($b, $c, $d, $a, $m, 11, 22, $T[11]);
$a = ff($a, $b, $c, $d, $m, 12, 17, $T[12]);
$d = ff($d, $a, $b, $c, $m, 13, 12, $T[13]);
$c = ff($c, $d, $a, $b, $m, 14, 17, $T[14]);
$b = ff($b, $c, $d, $a, $m, 15, 22, $T[15]);
// ROUND 2
$a = gg($a, $b, $c, $d, $m, 1, 5, $T[16]);
$d = gg($d, $a, $b, $c, $m, 6, 9, $T[17]);
$c = gg($c, $d, $a, $b, $m, 11, 14, $T[18]);
$b = gg($b, $c, $d, $a, $m, 0, 20, $T[19]);
$a = gg($a, $b, $c, $d, $m, 5, 5, $T[20]);
$d = gg($d, $a, $b, $c, $m, 10, 9, $T[21]);
$c = gg($c, $d, $a, $b, $m, 15, 14, $T[22]);
$b = gg($b, $c, $d, $a, $m, 4, 20, $T[23]);
$a = gg($a, $b, $c, $d, $m, 9, 5, $T[24]);
$d = gg($d, $a, $b, $c, $m, 14, 9, $T[25]);
$c = gg($c, $d, $a, $b, $m, 3, 14, $T[26]);
$b = gg($b, $c, $d, $a, $m, 8, 20, $T[27]);
$a = gg($a, $b, $c, $d, $m, 13, 5, $T[28]);
$d = gg($d, $a, $b, $c, $m, 2, 9, $T[29]);
$c = gg($c, $d, $a, $b, $m, 7, 14, $T[30]);
$b = gg($b, $c, $d, $a, $m, 12, 20, $T[31]);
// ROUND 3
$a = hh($a, $b, $c, $d, $m, 5, 4, $T[32]);
$d = hh($d, $a, $b, $c, $m, 8, 11, $T[33]);
$c = hh($c, $d, $a, $b, $m, 11, 16, $T[34]);
$b = hh($b, $c, $d, $a, $m, 14, 23, $T[35]);
$a = hh($a, $b, $c, $d, $m, 1, 4, $T[36]);
$d = hh($d, $a, $b, $c, $m, 4, 11, $T[37]);
$c = hh($c, $d, $a, $b, $m, 7, 16, $T[38]);
$b = hh($b, $c, $d, $a, $m, 10, 23, $T[39]);
$a = hh($a, $b, $c, $d, $m, 13, 4, $T[40]);
$d = hh($d, $a, $b, $c, $m, 0, 11, $T[41]);
$c = hh($c, $d, $a, $b, $m, 3, 16, $T[42]);
$b = hh($b, $c, $d, $a, $m, 6, 23, $T[43]);
$a = hh($a, $b, $c, $d, $m, 9, 4, $T[44]);
$d = hh($d, $a, $b, $c, $m, 12, 11, $T[45]);
$c = hh($c, $d, $a, $b, $m, 15, 16, $T[46]);
$b = hh($b, $c, $d, $a, $m, 2, 23, $T[47]);
// ROUND 4
$a = ii($a, $b, $c, $d, $m, 0, 6, $T[48]);
$d = ii($d, $a, $b, $c, $m, 7, 10, $T[49]);
$c = ii($c, $d, $a, $b, $m, 14, 15, $T[50]);
$b = ii($b, $c, $d, $a, $m, 5, 21, $T[51]);
$a = ii($a, $b, $c, $d, $m, 12, 6, $T[52]);
$d = ii($d, $a, $b, $c, $m, 3, 10, $T[53]);
$c = ii($c, $d, $a, $b, $m, 10, 15, $T[54]);
$b = ii($b, $c, $d, $a, $m, 1, 21, $T[55]);
$a = ii($a, $b, $c, $d, $m, 8, 6, $T[56]);
$d = ii($d, $a, $b, $c, $m, 15, 10, $T[57]);
$c = ii($c, $d, $a, $b, $m, 6, 15, $T[58]);
$b = ii($b, $c, $d, $a, $m, 13, 21, $T[59]);
$a = ii($a, $b, $c, $d, $m, 4, 6, $T[60]);
$d = ii($d, $a, $b, $c, $m, 11, 10, $T[61]);
$c = ii($c, $d, $a, $b, $m, 2, 15, $T[62]);
$b = ii($b, $c, $d, $a, $m, 9, 21, $T[63]);
$a = ADDxy($a, $aa);
$b = ADDxy($b, $bb);
$c = ADDxy($c, $cc);
$d = ADDxy($d, $dd);
// ECHO RESULTS
echo "<h1>String</h1><br>";
echo "String: '$string'<br>";
$md5 = md5($string);
echo "MD5: $md5<br><br>";
$md5_1 = substr($md5, 0, ;
$md5_2 = substr($md5, 8, ;
$md5_3 = substr($md5, 16, ;
$md5_4 = substr($md5, 24, ;
echo "A = $md5_1<br>B = $md5_2<br>C = $md5_3<br>D = $md5_4<br><br>";
$md5_bin_a = Pad(decbin(hexdec($md5_1)), 32);
$md5_bin_b = Pad(decbin(hexdec($md5_2)), 32);
$md5_bin_c = Pad(decbin(hexdec($md5_3)), 32);
$md5_bin_d = Pad(decbin(hexdec($md5_4)), 32);
echo "A = $md5_bin_a<br>B = $md5_bin_b<br>C = $md5_bin_c<br>D = $md5_bin_d<br><br>";
echo "<h1>Results</h1><br>";
echo "A = $a<br>B = $b<br>C = $c<br>D = $d<br><br>";
$a_dec = bindec($a);
$b_dec = bindec($b);
$c_dec = bindec($c);
$d_dec = bindec($d);
$a_hex = dechex($a_dec);
$b_hex = dechex($b_dec);
$c_hex = dechex($c_dec);
$d_hex = dechex($d_dec);
echo "A = $a_hex<br>B = $b_hex<br>C = $c_hex<br>D = $d_hex<br><br>";
// FUNCTIONS
function ff($a, $b, $c, $d, $m, $k, $s, $t) {
//a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s)
return ADDxy($b, SHIFTleft(ADDxy(ADDxy(ADDxy($a, F($b, $c, $d)), $m[$k]), $t), $s));
}
function gg($a, $b, $c, $d, $m, $k, $s, $t) {
//a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s)
return ADDxy($b, SHIFTleft(ADDxy(ADDxy(ADDxy($a, G($b, $c, $d)), $m[$k]), $t), $s));
}
function hh($a, $b, $c, $d, $m, $k, $s, $t) {
//a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s)
return ADDxy($b, SHIFTleft(ADDxy(ADDxy(ADDxy($a, H($b, $c, $d)), $m[$k]), $t), $s));
}
function ii($a, $b, $c, $d, $m, $k, $s, $t) {
//a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s)
return ADDxy($b, SHIFTleft(ADDxy(ADDxy(ADDxy($a, I($b, $c, $d)), $m[$k]), $t), $s));
}
function F($X, $Y, $Z) {
//return ($X & $Y) | ((~$X) & $Z);
return ORxy(ANDxy($X, $Y), ANDxy(NOTx($X), $Z));
}
function G($X, $Y, $Z) {
//return ($X & $Z) | ($Y & (~$Z));
return ORxy(ANDxy($X, $Z), ANDxy($Y, NOTx($Z)));
}
function H($X, $Y, $Z) {
//return $X ^ $Y ^ $Z;
return XORxy(XORxy($X, $Y), $Z);
}
function I($X, $Y, $Z) {
//return $Y ^ ($X | (~$Z));
return XORxy($Y, ORxy($X, NOTx($Z)));
}
function Pad($binary, $pad_length) {
$pad_length = $pad_length - strlen($binary);
for($i = 0; $i < $pad_length; $i++) {
$padding .= '0';
}
return $padding . $binary;
}
function mod($val, $div) {
$r = $val - (floor($val/$div)*$div);
return $r;
}
function ANDxy($x, $y) {
$x_dec = bindec($x);
$y_dec = bindec($y);
$result = $x_dec & $y_dec;
$result = Pad(decbin($result), strlen($x));
return $result;
}
function ORxy($x, $y) {
$x_dec = bindec($x);
$y_dec = bindec($y);
$result = $x_dec | $y_dec;
$result = Pad(decbin($result), strlen($x));
return $result;
}
function ADDxy($x, $y) {
$x_dec = bindec($x);
$y_dec = bindec($y);
$result = mod($x_dec + $y_dec, pow(2, 32));
$result = Pad(decbin($result), strlen($x));
return $result;
}
function XORxy($x, $y) {
$x_dec = bindec($x);
$y_dec = bindec($y);
$result = $x_dec ^ $y_dec;
$result = Pad(decbin($result), strlen($x));
return $result;
}
function NOTx($x) {
$x_dec = bindec($x);
$result = ~$x_dec;
$result = Pad(decbin($result), strlen($x));
return $result;
}
function SHIFTleft($x, $y) {
$x_dec = bindec($x);
$result = $x_dec << $y;
$result = Pad(decbin($result), strlen($x));
return $result;
}
function SHIFTright($x, $y) {
$x_dec = bindec($x);
$result = $x_dec >> $y;
$result = Pad(decbin($result), strlen($x));
return $result;
}
?>