reset(); } public function append($contents) { $this->_buff .= $contents; $this->_length += $this->strLen($contents); $length = $this->strLen($this->_buff); for ($i = 64; $i <= $length; $i += 64) { $this->md5cycle($this->md5blk($this->substr($this->_buff, $i - 64, $i))); } $this->_buff = $this->substr($this->_buff, $i - 64, $i); return $this; } public function end() { $buff = $this->_buff; $length = $this->strLen($buff); $tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; for ($i = 0; $i < $length; $i += 1) { $key = MD5Tool::INT32($i >> 2); $tail[$key] = MD5Tool::INT32($tail[$key] | MD5Tool::INT32($this->uniord($buff[$i]) << MD5Tool::INT32(($i % 4) << 3))); } echo "tail:"; print_r($tail); $this->_finish($tail, $length); echo "_hash:"; print_r($this->_hash); $md5 = $this->hex($this->_hash); $this->reset(); return strtoupper($md5); } public function getState() { return array( 'buff' => $this->_buff, 'length' => $this->_length, 'hash' => $this->_hash ); } public function setState($state) { if ($state && $state['hash']) { $state = $this->formatState($state); $this->_buff = $state['buff']; $this->_length = $state['length']; $this->_hash = $state['hash']; } return $this; } private function formatState($state) { if ($state['hash']) { foreach ($state['hash'] as &$hashVal) { $hashVal = intval($hashVal); } } if ($state['length']) { $state['length'] = intval($state['length']); } return $state; } private function reset() { $this->_buff = ''; $this->_length = 0; $this->_hash = [1732584193, -271733879, -1732584194, 271733878]; return $this; } private function hex($bin) { $hex_tab = "0123456789abcdef"; $str = ""; for ($i = 0; $i < count($bin) * 4; $i++) { $hexTabKey1 = MD5Tool::INT32(MD5Tool::INT32($bin[MD5Tool::INT32($i >> 2)] >> (($i % 4) * 8 + 4)) & 0xF); $hexTabKey2 = MD5Tool::INT32(MD5Tool::INT32($bin[MD5Tool::INT32($i >> 2)] >> (($i % 4) * 8 )) & 0xF); $str .= $hex_tab[$hexTabKey1] . $hex_tab[$hexTabKey2]; } return $str; } private function _finish($tail, $length) { $key = MD5Tool::INT32($length >> 2); $tail[$key] = MD5Tool::INT32($tail[$key] | MD5Tool::INT32(0x80 << MD5Tool::INT32(($length % 4) << 3))); if ($length > 55) { $this->md5cycle($tail); for ($i = 0; $i < 16; $i += 1) { $tail[$i] = 0; } } $tmp = base_convert($this->_length * 8, 10, 16); preg_match('/(.*)(.{0,8})$/isU', $tmp, $match); echo "match
"; print_r($match); $lo = base_convert($match[2], 16, 10); $hi = base_convert($match[1], 16, 10) ? : 0; $tail[14] = $lo; $tail[15] = $hi; $this->md5cycle($tail); } private function strLen($str) { return strlen($str); } private function substr($str, $start, $len) { return substr($str, $start, $len); } private function md5cycle($x) { $a = $this->_hash[0]; $b = $this->_hash[1]; $c = $this->_hash[2]; $d = $this->_hash[3]; MD5Tool::FF($a, $b, $c, $d, $x[0], MD5Tool::S11, 0xd76aa478); /* 1 */ echo "
a: $a;b:$b;c:$c;d:$d"; MD5Tool::FF($d, $a, $b, $c, $x[1], MD5Tool::S12, 0xe8c7b756); /* 2 */ echo "
a: $a;b:$b;c:$c;d:$d"; MD5Tool::FF($c, $d, $a, $b, $x[2], MD5Tool::S13, 0x242070db); /* 3 */ MD5Tool::FF($b, $c, $d, $a, $x[3], MD5Tool::S14, 0xc1bdceee); /* 4 */ echo "
a: $a;b:$b;c:$c;d:$d"; MD5Tool::FF($a, $b, $c, $d, $x[4], MD5Tool::S11, 0xf57c0faf); /* 5 */ MD5Tool::FF($d, $a, $b, $c, $x[5], MD5Tool::S12, 0x4787c62a); /* 6 */ MD5Tool::FF($c, $d, $a, $b, $x[6], MD5Tool::S13, 0xa8304613); /* 7 */ MD5Tool::FF($b, $c, $d, $a, $x[7], MD5Tool::S14, 0xfd469501); /* 8 */ MD5Tool::FF($a, $b, $c, $d, $x[8], MD5Tool::S11, 0x698098d8); /* 9 */ MD5Tool::FF($d, $a, $b, $c, $x[9], MD5Tool::S12, 0x8b44f7af); /* 10 */ MD5Tool::FF($c, $d, $a, $b, $x[10], MD5Tool::S13, 0xffff5bb1); /* 11 */ MD5Tool::FF($b, $c, $d, $a, $x[11], MD5Tool::S14, 0x895cd7be); /* 12 */ MD5Tool::FF($a, $b, $c, $d, $x[12], MD5Tool::S11, 0x6b901122); /* 13 */ MD5Tool::FF($d, $a, $b, $c, $x[13], MD5Tool::S12, 0xfd987193); /* 14 */ MD5Tool::FF($c, $d, $a, $b, $x[14], MD5Tool::S13, 0xa679438e); /* 15 */ MD5Tool::FF($b, $c, $d, $a, $x[15], MD5Tool::S14, 0x49b40821); /* 16 */ MD5Tool::GG($a, $b, $c, $d, $x[1], MD5Tool::S21, 0xf61e2562); /* 17 */ MD5Tool::GG($d, $a, $b, $c, $x[6], MD5Tool::S22, 0xc040b340); /* 18 */ MD5Tool::GG($c, $d, $a, $b, $x[11], MD5Tool::S23, 0x265e5a51); /* 19 */ MD5Tool::GG($b, $c, $d, $a, $x[0], MD5Tool::S24, 0xe9b6c7aa); /* 20 */ MD5Tool::GG($a, $b, $c, $d, $x[5], MD5Tool::S21, 0xd62f105d); /* 21 */ MD5Tool::GG($d, $a, $b, $c, $x[10], MD5Tool::S22, 0x2441453); /* 22 */ MD5Tool::GG($c, $d, $a, $b, $x[15], MD5Tool::S23, 0xd8a1e681); /* 23 */ MD5Tool::GG($b, $c, $d, $a, $x[4], MD5Tool::S24, 0xe7d3fbc8); /* 24 */ MD5Tool::GG($a, $b, $c, $d, $x[9], MD5Tool::S21, 0x21e1cde6); /* 25 */ MD5Tool::GG($d, $a, $b, $c, $x[14], MD5Tool::S22, 0xc33707d6); /* 26 */ MD5Tool::GG($c, $d, $a, $b, $x[3], MD5Tool::S23, 0xf4d50d87); /* 27 */ MD5Tool::GG($b, $c, $d, $a, $x[8], MD5Tool::S24, 0x455a14ed); /* 28 */ MD5Tool::GG($a, $b, $c, $d, $x[13], MD5Tool::S21, 0xa9e3e905); /* 29 */ MD5Tool::GG($d, $a, $b, $c, $x[2], MD5Tool::S22, 0xfcefa3f8); /* 30 */ MD5Tool::GG($c, $d, $a, $b, $x[7], MD5Tool::S23, 0x676f02d9); /* 31 */ MD5Tool::GG($b, $c, $d, $a, $x[12], MD5Tool::S24, 0x8d2a4c8a); /* 32 */ MD5Tool::HH($a, $b, $c, $d, $x[5], MD5Tool::S31, 0xfffa3942); /* 33 */ MD5Tool::HH($d, $a, $b, $c, $x[8], MD5Tool::S32, 0x8771f681); /* 34 */ MD5Tool::HH($c, $d, $a, $b, $x[11], MD5Tool::S33, 0x6d9d6122); /* 35 */ MD5Tool::HH($b, $c, $d, $a, $x[14], MD5Tool::S34, 0xfde5380c); /* 36 */ MD5Tool::HH($a, $b, $c, $d, $x[1], MD5Tool::S31, 0xa4beea44); /* 37 */ MD5Tool::HH($d, $a, $b, $c, $x[4], MD5Tool::S32, 0x4bdecfa9); /* 38 */ MD5Tool::HH($c, $d, $a, $b, $x[7], MD5Tool::S33, 0xf6bb4b60); /* 39 */ MD5Tool::HH($b, $c, $d, $a, $x[10], MD5Tool::S34, 0xbebfbc70); /* 40 */ MD5Tool::HH($a, $b, $c, $d, $x[13], MD5Tool::S31, 0x289b7ec6); /* 41 */ MD5Tool::HH($d, $a, $b, $c, $x[0], MD5Tool::S32, 0xeaa127fa); /* 42 */ MD5Tool::HH($c, $d, $a, $b, $x[3], MD5Tool::S33, 0xd4ef3085); /* 43 */ MD5Tool::HH($b, $c, $d, $a, $x[6], MD5Tool::S34, 0x4881d05); /* 44 */ MD5Tool::HH($a, $b, $c, $d, $x[9], MD5Tool::S31, 0xd9d4d039); /* 45 */ MD5Tool::HH($d, $a, $b, $c, $x[12], MD5Tool::S32, 0xe6db99e5); /* 46 */ MD5Tool::HH($c, $d, $a, $b, $x[15], MD5Tool::S33, 0x1fa27cf8); /* 47 */ MD5Tool::HH($b, $c, $d, $a, $x[2], MD5Tool::S34, 0xc4ac5665); /* 48 */ MD5Tool::II($a, $b, $c, $d, $x[0], MD5Tool::S41, 0xf4292244); /* 49 */ MD5Tool::II($d, $a, $b, $c, $x[7], MD5Tool::S42, 0x432aff97); /* 50 */ MD5Tool::II($c, $d, $a, $b, $x[14], MD5Tool::S43, 0xab9423a7); /* 51 */ MD5Tool::II($b, $c, $d, $a, $x[5], MD5Tool::S44, 0xfc93a039); /* 52 */ MD5Tool::II($a, $b, $c, $d, $x[12], MD5Tool::S41, 0x655b59c3); /* 53 */ MD5Tool::II($d, $a, $b, $c, $x[3], MD5Tool::S42, 0x8f0ccc92); /* 54 */ MD5Tool::II($c, $d, $a, $b, $x[10], MD5Tool::S43, 0xffeff47d); /* 55 */ MD5Tool::II($b, $c, $d, $a, $x[1], MD5Tool::S44, 0x85845dd1); /* 56 */ MD5Tool::II($a, $b, $c, $d, $x[8], MD5Tool::S41, 0x6fa87e4f); /* 57 */ MD5Tool::II($d, $a, $b, $c, $x[15], MD5Tool::S42, 0xfe2ce6e0); /* 58 */ MD5Tool::II($c, $d, $a, $b, $x[6], MD5Tool::S43, 0xa3014314); /* 59 */ MD5Tool::II($b, $c, $d, $a, $x[13], MD5Tool::S44, 0x4e0811a1); /* 60 */ MD5Tool::II($a, $b, $c, $d, $x[4], MD5Tool::S41, 0xf7537e82); /* 61 */ MD5Tool::II($d, $a, $b, $c, $x[11], MD5Tool::S42, 0xbd3af235); /* 62 */ MD5Tool::II($c, $d, $a, $b, $x[2], MD5Tool::S43, 0x2ad7d2bb); /* 63 */ MD5Tool::II($b, $c, $d, $a, $x[9], MD5Tool::S44, 0xeb86d391); /* 64 */ echo "
a: $a;b:$b;c:$c;d:$d"; echo "_hash start:"; print_r($this->_hash); $this->_hash[0] = intval($this->_hash[0] + $a); $this->_hash[1] = intval($this->_hash[1] + $b); $this->_hash[2] = intval($this->_hash[2] + $c); $this->_hash[3] = intval($this->_hash[3] + $d); echo "_hash end:"; print_r($this->_hash); } private function md5blk($str) { $md5blks = []; for ($i = 0; $i < 64; $i += 4) { $val = 0; for ($j = 0; $j <= 3; $j++) { $val += MD5Tool::INT32($this->uniord($str[$i + $j]) << ($j * 8)); } $md5blks[MD5Tool::INT32($i >> 2)] = $val; } return $md5blks; } private function uniord($str, $from_encoding=false){ $from_encoding=$from_encoding ? $from_encoding : 'UTF-8'; if(strlen($str)==1){ return ord($str);} $str= mb_convert_encoding($str, 'UCS-4BE', $from_encoding); $tmp= unpack('N',$str); return $tmp[1]; } public function testMD5ToolURShift($a, $b) { echo MD5Tool::URShift($a, $b); } public function testMD5ToolROTATELEFT($a, $b) { echo MD5Tool::ROTATE_LEFT($a, $b); } } class MD5Tool { const S11 = 7; const S12 = 12; const S13 = 17; const S14 = 22; const S21 = 5; const S22 = 9; const S23 = 14; const S24 = 20; const S31 = 4; const S32 = 11; const S33 = 16; const S34 = 23; const S41 = 6; const S42 = 10; const S43 = 15; const S44 = 21; public static function F($x, $y, $z) { return MD5Tool::INT32(MD5Tool::INT32($x & $y) | MD5Tool::INT32(MD5Tool::INT32(~$x) & $z)); } public static function G($x, $y, $z) { return MD5Tool::INT32(MD5Tool::INT32($x & $z) | MD5Tool::INT32($y & MD5Tool::INT32(~$z))); } public static function H($x, $y, $z) { return MD5Tool::INT32(MD5Tool::INT32($x ^ $y) ^ $z); } public static function I($x, $y, $z) { return MD5Tool::INT32($y ^ MD5Tool::INT32($x | MD5Tool::INT32(~$z))); } public static function ROTATE_LEFT($x, $n) { return MD5Tool::INT32(MD5Tool::INT32($x << $n) | self::URShift($x, (32 - $n))); } public static function URShift($x, $bits) { $bin = decbin($x); $len = strlen($bin); if ($len > 32) { $bin = substr($bin, $len - 32, 32); } elseif ($len < 32) { $bin = str_pad($bin, 32, '0', STR_PAD_LEFT); } return bindec(str_pad(substr($bin, 0, 32 - $bits), 32, '0', STR_PAD_LEFT)); } public static function FF(&$a, $b, $c, $d, $x, $s, $ac) { $a += self::F($b, $c, $d) + ($x) + $ac; $a = self::ROTATE_LEFT($a, $s); $a = intval($a + $b); } public static function GG(&$a, $b, $c, $d, $x, $s, $ac) { $a += self::G($b, $c, $d) + ($x) + $ac; $a = self::ROTATE_LEFT($a, $s); $a = intval($a + $b); } public static function HH(&$a, $b, $c, $d, $x, $s, $ac) { $a += self::H($b, $c, $d) + ($x) + $ac; $a = self::ROTATE_LEFT($a, $s); $a = intval($a + $b); } public static function II(&$a, $b, $c, $d, $x, $s, $ac) { $a += self::I($b, $c, $d) + ($x) + $ac; $a = self::ROTATE_LEFT($a, $s); $a = intval($a + $b); } public static function INT32($value) { $value = ($value & 0xFFFFFFFF); if ($value & 0x80000000) $value = -((~$value & 0xFFFFFFFF) + 1); return $value; } }