Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>For some reason this question didn't leave me alone, so I went through your code and fixed the bugs until it worked:</p> <p>Before you go through this, I have two pieces of advice:</p> <ol> <li><p>Don't convert back and forth between int values and hex/bin representations; convert to int values before any processing is done; makes the code much more readable.</p></li> <li><p>Use <a href="http://us2.php.net/manual/en/function.call-user-func.php" rel="noreferrer"><code>call_user_func()</code></a> and implement the GG -> G, II -> I functions only once.</p></li> </ol> <p>Also, there is one subtle bug remaining; an input string made up exclusively of zero characters will not be encoded correctly; I'll leave fixing that as an exercise for the reader :-).</p> <ul> <li>In <code>init()</code>:</li> </ul> <p>What is appended is the length of the unpadded message in number of <strong>bits</strong>, not number of characters:</p> <pre><code>- $len = strlen($string) + $len = strlen($string) * 8; $hex = strhex($string); // convert ascii string to hex </code></pre> <p>also, you have to pad what you get from <code>hexbin</code> otherwise the subsequent call to <code>str_split</code> will get the alignment wrong:</p> <pre><code>- $bin = hexbin($hex); + $bin = leftpad(hexbin($hex), $len); // convert hex string to bin $block = str_split($padded, 32); </code></pre> <p>also, the byte order is little endian:</p> <pre><code>+ foreach ($block as &amp;$b) { + $b = implode('', array_reverse(str_split($b, 8))); + } </code></pre> <ul> <li>In <code>strhex()</code>:</li> </ul> <p>There are a lot of padding errors like this; <code>dechex(ord("\1"))</code> is <code>'1'</code> not <code>'01'</code>:</p> <pre><code>- $hex = $hex.dechex(ord($str[$i])); + $hex = $hex.leftpad(dechex(ord($str[$i])), 2); </code></pre> <ul> <li>In <code>pad()</code>:</li> </ul> <p>The <strong>byte</strong>-order is litte endian (you're splitting into 32-bit words) and <code>truncate64()</code> is completely off the map :-):</p> <pre><code>- $bLen = decbin($len); - if(strlen($bLen) &gt; 64){ - $words = truncate64($bLen); - $bin .= $words[1].$words[0]; - } - else{ - while(strlen($bLen) &lt; 64){ - $bLen .= "0"; - } - $words = str_split ($bLen, 32); - $bin .= $words[1].$words[0]; - } + $bLen = leftpad(decbin($len), 64); + $bin .= implode('', array_reverse(str_split($bLen, 8))); </code></pre> <ul> <li>In <code>F()</code>, <code>G()</code>, <code>H()</code>, <code>I()</code>:</li> </ul> <p>Bitwise operators can't be used on binary strings:</p> <pre><code>- $X = hexbin($X); - $Y = hexbin($Y); - $Z = hexbin($Z); - $calc = ... - $calc = bindec($calc); + $X = hexdec($X); + $Y = hexdec($Y); + $Z = hexdec($Z); + $calc = ... </code></pre> <ul> <li>In <code>FF()</code>, <code>GG()</code>, <code>HH()</code>, <code>II()</code>:</li> </ul> <p>You are adding <code>$B</code> before rotation, it must be added afterwards; also, since you are going back and forth between string and int representations and <code>PHP_INT_SIZE</code> may be greater than 4 (e.g. on 64-bit platforms), you have to make sure you only use the lower 32-bits:</p> <pre><code>- $A = hexdec($B) + (($A + H($B, $C, $D) + $M + $t)); //decimal + $A = ($A + H($B, $C, $D) + $M + $t) &amp; 0xffffffff; //decimal + $A = rotate($A, $s); + $A = dechex((hexdec($B) + hexdec($A)) &amp; 0xffffffff); </code></pre> <ul> <li>In <code>addVars()</code>:</li> </ul> <p><code>$A</code> is repeated for each addition, probably a copy-paste artifact :-):</p> <pre><code>- $aa = $aa + $A; - $bb = $bb + $A; - $cc = $cc + $A; - $dd = $dd + $A; + $aa = ($aa + $A) &amp; 0xffffffff; + $bb = ($bb + $B) &amp; 0xffffffff; + $cc = ($cc + $C) &amp; 0xffffffff; + $dd = ($dd + $D) &amp; 0xffffffff; </code></pre> <ul> <li>In <code>rotate()</code>:</li> </ul> <p>There is a padding bug (again) in your rotate function. Just throw it away and replace it with:</p> <pre><code>+ function rotate ($decimal, $bits) { //returns hex + return dechex((($decimal &lt;&lt; $bits) | ($decimal &gt;&gt; (32 - $bits))) &amp; 0xffffffff); + } </code></pre> <ul> <li>In <code>MD()</code>:</li> </ul> <p>Last but not least, you have to convert to little endian again:</p> <pre><code>- $MD5 = $a.$b.$c.$d; + $MD5 = ''; + foreach (array($a, $b, $c, $d) as $x) { + $MD5 .= implode('', array_reverse(str_split(leftpad($x, 8), 2))); + } </code></pre> <p>The missing <code>leftpad()</code> function:</p> <pre><code>+ function leftpad($needs_padding, $alignment) + { + if (strlen($needs_padding) % $alignment) { + $pad_amount = $alignment - strlen($needs_padding) % $alignment; + $left_pad = implode('', array_fill(0, $pad_amount, '0')); + $needs_padding = $left_pad . $needs_padding; + } + return $needs_padding; + } </code></pre> <p>Full edited source:</p> <pre><code>&lt;?php function MD($string){ $a = "67452301"; $b = "EFCDAB89"; $c = "98BADCFE"; $d = "10325476"; $words = init($string); for($i = 0; $i &lt;= count($words)/16-1; $i++){ $A = $a; $B = $b; $C = $c; $D = $d; /* ROUND 1 */ FF ($A, $B, $C, $D, $words[0 + ($i * 16)], 7, "d76aa478"); FF ($D, $A, $B, $C, $words[1 + ($i * 16)], 12, "e8c7b756"); FF ($C, $D, $A, $B, $words[2 + ($i * 16)], 17, "242070db"); FF ($B, $C, $D, $A, $words[3 + ($i * 16)], 22, "c1bdceee"); FF ($A, $B, $C, $D, $words[4 + ($i * 16)], 7, "f57c0faf"); FF ($D, $A, $B, $C, $words[5 + ($i * 16)], 12, "4787c62a"); FF ($C, $D, $A, $B, $words[6 + ($i * 16)], 17, "a8304613"); FF ($B, $C, $D, $A, $words[7 + ($i * 16)], 22, "fd469501"); FF ($A, $B, $C, $D, $words[8 + ($i * 16)], 7, "698098d8"); FF ($D, $A, $B, $C, $words[9 + ($i * 16)], 12, "8b44f7af"); FF ($C, $D, $A, $B, $words[10 + ($i * 16)], 17, "ffff5bb1"); FF ($B, $C, $D, $A, $words[11 + ($i * 16)], 22, "895cd7be"); FF ($A, $B, $C, $D, $words[12 + ($i * 16)], 7, "6b901122"); FF ($D, $A, $B, $C, $words[13 + ($i * 16)], 12, "fd987193"); FF ($C, $D, $A, $B, $words[14 + ($i * 16)], 17, "a679438e"); FF ($B, $C, $D, $A, $words[15 + ($i * 16)], 22, "49b40821"); /* ROUND 2 */ GG ($A, $B, $C, $D, $words[1 + ($i * 16)], 5, "f61e2562"); GG ($D, $A, $B, $C, $words[6 + ($i * 16)], 9, "c040b340"); GG ($C, $D, $A, $B, $words[11 + ($i * 16)], 14, "265e5a51"); GG ($B, $C, $D, $A, $words[0 + ($i * 16)], 20, "e9b6c7aa"); GG ($A, $B, $C, $D, $words[5 + ($i * 16)], 5, "d62f105d"); GG ($D, $A, $B, $C, $words[10 + ($i * 16)], 9, "02441453"); GG ($C, $D, $A, $B, $words[15 + ($i * 16)], 14, "d8a1e681"); GG ($B, $C, $D, $A, $words[4 + ($i * 16)], 20, "e7d3fbc8"); GG ($A, $B, $C, $D, $words[9 + ($i * 16)], 5, "21e1cde6"); GG ($D, $A, $B, $C, $words[14 + ($i * 16)], 9, "c33707d6"); GG ($C, $D, $A, $B, $words[3 + ($i * 16)], 14, "f4d50d87"); GG ($B, $C, $D, $A, $words[8 + ($i * 16)], 20, "455a14ed"); GG ($A, $B, $C, $D, $words[13 + ($i * 16)], 5, "a9e3e905"); GG ($D, $A, $B, $C, $words[2 + ($i * 16)], 9, "fcefa3f8"); GG ($C, $D, $A, $B, $words[7 + ($i * 16)], 14, "676f02d9"); GG ($B, $C, $D, $A, $words[12 + ($i * 16)], 20, "8d2a4c8a"); /* ROUND 3 */ HH ($A, $B, $C, $D, $words[5 + ($i * 16)], 4, "fffa3942"); HH ($D, $A, $B, $C, $words[8 + ($i * 16)], 11, "8771f681"); HH ($C, $D, $A, $B, $words[11 + ($i * 16)], 16, "6d9d6122"); HH ($B, $C, $D, $A, $words[14 + ($i * 16)], 23, "fde5380c"); HH ($A, $B, $C, $D, $words[1 + ($i * 16)], 4, "a4beea44"); HH ($D, $A, $B, $C, $words[4 + ($i * 16)], 11, "4bdecfa9"); HH ($C, $D, $A, $B, $words[7 + ($i * 16)], 16, "f6bb4b60"); HH ($B, $C, $D, $A, $words[10 + ($i * 16)], 23, "bebfbc70"); HH ($A, $B, $C, $D, $words[13 + ($i * 16)], 4, "289b7ec6"); HH ($D, $A, $B, $C, $words[0 + ($i * 16)], 11, "eaa127fa"); HH ($C, $D, $A, $B, $words[3 + ($i * 16)], 16, "d4ef3085"); HH ($B, $C, $D, $A, $words[6 + ($i * 16)], 23, "04881d05"); HH ($A, $B, $C, $D, $words[9 + ($i * 16)], 4, "d9d4d039"); HH ($D, $A, $B, $C, $words[12 + ($i * 16)], 11, "e6db99e5"); HH ($C, $D, $A, $B, $words[15 + ($i * 16)], 16, "1fa27cf8"); HH ($B, $C, $D, $A, $words[2 + ($i * 16)], 23, "c4ac5665"); /* ROUND 4 */ II ($A, $B, $C, $D, $words[0 + ($i * 16)], 6, "f4292244"); II ($D, $A, $B, $C, $words[7 + ($i * 16)], 10, "432aff97"); II ($C, $D, $A, $B, $words[14 + ($i * 16)], 15, "ab9423a7"); II ($B, $C, $D, $A, $words[5 + ($i * 16)], 21, "fc93a039"); II ($A, $B, $C, $D, $words[12 + ($i * 16)], 6, "655b59c3"); II ($D, $A, $B, $C, $words[3 + ($i * 16)], 10, "8f0ccc92"); II ($C, $D, $A, $B, $words[10 + ($i * 16)], 15, "ffeff47d"); II ($B, $C, $D, $A, $words[1 + ($i * 16)], 21, "85845dd1"); II ($A, $B, $C, $D, $words[8 + ($i * 16)], 6, "6fa87e4f"); II ($D, $A, $B, $C, $words[15 + ($i * 16)], 10, "fe2ce6e0"); II ($C, $D, $A, $B, $words[6 + ($i * 16)], 15, "a3014314"); II ($B, $C, $D, $A, $words[13 + ($i * 16)], 21, "4e0811a1"); II ($A, $B, $C, $D, $words[4 + ($i * 16)], 6, "f7537e82"); II ($D, $A, $B, $C, $words[11 + ($i * 16)], 10, "bd3af235"); II ($C, $D, $A, $B, $words[2 + ($i * 16)], 15, "2ad7d2bb"); II ($B, $C, $D, $A, $words[9 + ($i * 16)], 21, "eb86d391"); addVars($a, $b, $c, $d, $A, $B, $C, $D); } $MD5 = ''; foreach (array($a, $b, $c, $d) as $x) { $MD5 .= implode('', array_reverse(str_split(leftpad($x, 8), 2))); } return $MD5; } /* General functions */ function hexbin($str){ $hexbinmap = array("0" =&gt; "0000" , "1" =&gt; "0001" , "2" =&gt; "0010" , "3" =&gt; "0011" , "4" =&gt; "0100" , "5" =&gt; "0101" , "6" =&gt; "0110" , "7" =&gt; "0111" , "8" =&gt; "1000" , "9" =&gt; "1001" , "A" =&gt; "1010" , "a" =&gt; "1010" , "B" =&gt; "1011" , "b" =&gt; "1011" , "C" =&gt; "1100" , "c" =&gt; "1100" , "D" =&gt; "1101" , "d" =&gt; "1101" , "E" =&gt; "1110" , "e" =&gt; "1110" , "F" =&gt; "1111" , "f" =&gt; "1111"); $bin = ""; for ($i = 0; $i &lt; strlen($str); $i++) { $bin .= $hexbinmap[$str[$i]]; } $bin = ltrim($bin, '0'); // echo "Original: ".$str." New: ".$bin."&lt;br /&gt;"; return $bin; } function strhex($str){ $hex = ""; for ($i = 0; $i &lt; strlen($str); $i++) { $hex = $hex.leftpad(dechex(ord($str[$i])), 2); } return $hex; } /* MD5-specific functions */ function init($string){ $len = strlen($string) * 8; $hex = strhex($string); // convert ascii string to hex $bin = leftpad(hexbin($hex), $len); // convert hex string to bin $padded = pad($bin); $padded = pad($padded, 1, $len); $block = str_split($padded, 32); foreach ($block as &amp;$b) { $b = implode('', array_reverse(str_split($b, 8))); } return $block; } function pad($bin, $type=0, $len = 0){ if($type == 0){ $bin = $bin."1"; $buff = strlen($bin) % 512; if($buff != 448){ while(strlen($bin) % 512 != 448){ $bin = $bin."0"; } } } // append length (b) of string to latter 64 bits elseif($type == 1){ $bLen = leftpad(decbin($len), 64); $bin .= implode('', array_reverse(str_split($bLen, 8))); } return $bin; } /* MD5 base functions */ function F($X, $Y, $Z){ $X = hexdec($X); $Y = hexdec($Y); $Z = hexdec($Z); $calc = (($X &amp; $Y) | ((~ $X) &amp; $Z)); // X AND Y OR NOT X AND Z return $calc; } function G($X, $Y, $Z){ $X = hexdec($X); $Y = hexdec($Y); $Z = hexdec($Z); $calc = (($X &amp; $Z) | ($Y &amp; (~ $Z))); // X AND Z OR Y AND NOT Z return $calc; } function H($X, $Y, $Z){ $X = hexdec($X); $Y = hexdec($Y); $Z = hexdec($Z); $calc = ($X ^ $Y ^ $Z); // X XOR Y XOR Z return $calc; } function I($X, $Y, $Z){ $X = hexdec($X); $Y = hexdec($Y); $Z = hexdec($Z); $calc = ($Y ^ ($X | (~ $Z))) ; // Y XOR (X OR NOT Z) return $calc; } /* MD5 round functions */ /* $A - hex, $B - hex, $C - hex, $D - hex (F - dec) $M - binary $s - decimal $t - hex */ function FF(&amp;$A, $B, $C, $D, $M, $s, $t){ $A = hexdec($A); $t = hexdec($t); $M = bindec($M); $A = ($A + F($B, $C, $D) + $M + $t) &amp; 0xffffffff; //decimal $A = rotate($A, $s); $A = dechex((hexdec($B) + hexdec($A)) &amp; 0xffffffff); } function GG(&amp;$A, $B, $C, $D, $M, $s, $t){ $A = hexdec($A); $t = hexdec($t); $M = bindec($M); $A = ($A + G($B, $C, $D) + $M + $t) &amp; 0xffffffff; //decimal $A = rotate($A, $s); $A = dechex((hexdec($B) + hexdec($A)) &amp; 0xffffffff); } function HH(&amp;$A, $B, $C, $D, $M, $s, $t){ $A = hexdec($A); $t = hexdec($t); $M = bindec($M); $A = ($A + H($B, $C, $D) + $M + $t) &amp; 0xffffffff; //decimal $A = rotate($A, $s); $A = dechex((hexdec($B) + hexdec($A)) &amp; 0xffffffff); } function II(&amp;$A, $B, $C, $D, $M, $s, $t){ $A = hexdec($A); $t = hexdec($t); $M = bindec($M); $A = ($A + I($B, $C, $D) + $M + $t) &amp; 0xffffffff; //decimal $A = rotate($A, $s); $A = dechex((hexdec($B) + hexdec($A)) &amp; 0xffffffff); } // shift function rotate ($decimal, $bits) { //returns hex return dechex((($decimal &lt;&lt; $bits) | ($decimal &gt;&gt; (32 - $bits))) &amp; 0xffffffff); } function addVars(&amp;$a, &amp;$b, &amp;$c, &amp;$d, $A, $B, $C, $D){ $A = hexdec($A); $B = hexdec($B); $C = hexdec($C); $D = hexdec($D); $aa = hexdec($a); $bb = hexdec($b); $cc = hexdec($c); $dd = hexdec($d); $aa = ($aa + $A) &amp; 0xffffffff; $bb = ($bb + $B) &amp; 0xffffffff; $cc = ($cc + $C) &amp; 0xffffffff; $dd = ($dd + $D) &amp; 0xffffffff; $a = dechex($aa); $b = dechex($bb); $c = dechex($cc); $d = dechex($dd); } function leftpad($needs_padding, $alignment) { if (strlen($needs_padding) % $alignment) { $pad_amount = $alignment - strlen($needs_padding) % $alignment; $left_pad = implode('', array_fill(0, $pad_amount, '0')); $needs_padding = $left_pad . $needs_padding; } return $needs_padding; } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload