As an exercise, I'm attempting to implement MD5 in PHP. I know PHP has a built-in function for this but I would like to read, run and study a working source. I found this script which works great when appropriate sections are uncommented (to enable message padding) and arrays are formatted accordingly (for compatibility for my version of PHP.) However the hash produced - despite being of correct length - is not MD5. For example, the MD5 hash for a zero length string should be:
d41d8cd98f00b204e9800998ecf8427e
but the hash returned by the script for the same is:
85bd946a585af9fd3fb9eda68707c1d8
I've tried other strings but there is no correlation. I've been studying MD5 so have a reasonable knowledge of how it works. I've been interrogating the script but it seems legitimate. I guess I'm giving a shout out to another up for the challenge of discovering why this script isn't returning MD5.
This script wasn't returning genuine MD5 hashes because there lay an issue with the rotation function.
PHP currently doesn't offer native bitwise rotation function(s). Nevertheless, bitwise rotation can be achieved by combining a left shift result and a right shift result. However, during right bit shifts on negative signed integers the sign bit is shifted in for sign-preservation of the operand; this has unwanted consequences and is overcome using a bit mask.
Where $x
is input value and $c
is number of bits to shift. All values are 32-bit.
Original Code:
`return ($x << $c) | ($x >> (32 - $c));`
New Code:
if($x < 0){
return ($x << $c) | abs( ((pow(2, $c)) * -1) - ($x >> (32 - $c)));
} else {
return ($x << $c) | ($x >> (32 - $c)) ;
}
I've deliberately left multiple spaces on line 4 to contrast with line 2 to show formula similarity and presence (or absence) of the bit mask.
Ternary formatted:
return ($x < 0) ? (($x << $c) | abs( ((pow(2, $c)) * -1) -
($x >> (32 - $c)))) : (($x << $c) | ($x >> (32 - $c)));