44
55class MD5
66{
7- // Context
8-
97 /**
108 * @var int
119 */
@@ -26,11 +24,17 @@ class MD5
2624 */
2725 private $ d ;
2826
27+ /**
28+ * @var int
29+ */
30+ private static $ allOneBits ;
31+
2932 /**
3033 * MD5 stream constructor.
3134 */
3235 public function __construct ()
3336 {
37+ self ::$ allOneBits = self ::signedInt (0xffffffff );
3438 $ this ->reset ();
3539 }
3640
@@ -40,8 +44,8 @@ public function __construct()
4044 public function reset (): void
4145 {
4246 $ this ->a = 0x67452301 ;
43- $ this ->b = 0xEFCDAB89 ;
44- $ this ->c = 0x98BADCFE ;
47+ $ this ->b = self :: signedInt ( 0xEFCDAB89 ) ;
48+ $ this ->c = self :: signedInt ( 0x98BADCFE ) ;
4549 $ this ->d = 0x10325476 ;
4650 }
4751
@@ -156,10 +160,10 @@ public function add(string $data): void
156160 self ::step ($ I , $ C , $ D , $ A , $ B , $ words [2 ], 15 , 0x2ad7d2bb );
157161 self ::step ($ I , $ B , $ C , $ D , $ A , $ words [9 ], 21 , 0xeb86d391 );
158162
159- $ this ->a = ($ this ->a + $ A ) & 0xffffffff ;
160- $ this ->b = ($ this ->b + $ B ) & 0xffffffff ;
161- $ this ->c = ($ this ->c + $ C ) & 0xffffffff ;
162- $ this ->d = ($ this ->d + $ D ) & 0xffffffff ;
163+ $ this ->a = ($ this ->a + $ A ) & self :: $ allOneBits ;
164+ $ this ->b = ($ this ->b + $ B ) & self :: $ allOneBits ;
165+ $ this ->c = ($ this ->c + $ C ) & self :: $ allOneBits ;
166+ $ this ->d = ($ this ->d + $ D ) & self :: $ allOneBits ;
163167 }
164168
165169 private static function f (int $ X , int $ Y , int $ Z ): int
@@ -182,18 +186,25 @@ private static function i(int $X, int $Y, int $Z): int
182186 return $ Y ^ ($ X | (~$ Z )); // Y XOR (X OR NOT Z)
183187 }
184188
185- private static function step (callable $ func , int &$ A , int $ B , int $ C , int $ D , int $ M , int $ s , int $ t ): void
189+ /** @param float|int $t may be float on 32-bit system */
190+ private static function step (callable $ func , int &$ A , int $ B , int $ C , int $ D , int $ M , int $ s , $ t ): void
186191 {
187- $ A = ($ A + call_user_func ($ func , $ B , $ C , $ D ) + $ M + $ t ) & 0xffffffff ;
192+ $ t = self ::signedInt ($ t );
193+ $ A = ($ A + call_user_func ($ func , $ B , $ C , $ D ) + $ M + $ t ) & self ::$ allOneBits ;
188194 $ A = self ::rotate ($ A , $ s );
189- $ A = ($ B + $ A ) & 0xffffffff ;
195+ $ A = ($ B + $ A ) & self ::$ allOneBits ;
196+ }
197+
198+ /** @param float|int $result may be float on 32-bit system */
199+ private static function signedInt ($ result ): int
200+ {
201+ return is_int ($ result ) ? $ result : (int ) (PHP_INT_MIN + $ result - 1 - PHP_INT_MAX );
190202 }
191203
192- /** @return float|int */
193- private static function rotate (int $ decimal , int $ bits )
204+ private static function rotate (int $ decimal , int $ bits ): int
194205 {
195206 $ binary = str_pad (decbin ($ decimal ), 32 , '0 ' , STR_PAD_LEFT );
196207
197- return bindec (substr ($ binary , $ bits ) . substr ($ binary , 0 , $ bits ));
208+ return self :: signedInt ( bindec (substr ($ binary , $ bits ) . substr ($ binary , 0 , $ bits) ));
198209 }
199210}
0 commit comments