一、什么是MD5加密?
MD5加密是一种单向加密算法,将任意长度的数据加密成固定长度的密文。主要被用于密码加密,数字签名等领域。
MD5加密特点:
1、加密结果是固定长度的128bit字符串,不管加密前数据的长度多长,密文长度始终为128bit。
2、同样的数据进行MD5加密后,生成的密文总是相同的。
3、密文经MD5加密后无法通过任何手段还原为明文。
二、MD5加密的实现原理
MD5加密通过对明文进行多次处理,生成固定长度的密文。处理过程主要包括以下几步:
1、填充
将明文进行长度扩展,使其长度满足448mod512,并在其末尾添加一个64bit的数据,用于保存明文本身的长度。
//填充函数
function padding($str){
$len = strlen($str); //得到字符串长度
$pad_len = 448 - $len % 512; //计算需要填充的长度
if($pad_len <= 64) //如果需要填充的长度介于1-64之间,则需要加一个分组
$pad_len += 512;
$pad_char = chr($pad_len/8); //计算需要填充的字符
$padding_str = "";
for($i=0; $i<$pad_len/8; $i++)
$padding_str .= $pad_char;
$padding_str .= $str.pack("Q*", $len*8); //连接原始数据长度
return $padding_str;
}
2、初始化
对填充后的明文进行初始化,生成4个32bit的缓存区,对应a、b、c、d。根据RFC1321规格定义的初始值,将a、b、c、d设置成如下值:
a = 0x67452301
b = 0xEFCDAB89
c= 0x98BADCFE
d=0x10325476
//初始化MD5状态变量
$A = 0x67452301;
$B = 0xEFCDAB89;
$C = 0x98BADCFE;
$D = 0x10325476;
3、四轮迭代
将初始化后的缓存区与每个512位的分组进行四轮迭代计算,每轮迭代对缓存区进行ABCD四个变量的置换。
//四轮迭代
function md5_loop($f, $m, $s, $i){
global $A, $B, $C, $D;
if($f == 'F')
$res = ($B & $C) | (~$B & $D);
else if($f == 'G')
$res = ($B & $D) | ($C & ~$D);
else if($f == 'H')
$res = ($B ^ $C ^ $D);
else if($f == 'I')
$res = ($C ^ ($B | ~$D));
$temp = $B + shiftleft(($A + $res + $m + $s[$i]), $i*5%32);
$A = $D;
$D = $C;
$C = $B;
$B = $temp;
}
//用于循环左移
function shiftleft($num, $bits){
$num = $num & 0xffffffff; //强制截断为32位
$num_str = decbin($num); //转换为二进制字符串
$num_str = str_pad($num_str, 32, 0, STR_PAD_LEFT); //补充0,使其长度变成32位
$num_str = substr($num_str, $bits).substr($num_str, 0, $bits); //将字符串分为两部分,分别进行循环左移
return bindec($num_str); //将处理结果返回为十进制数
}
4、生成密文
经过四轮迭代之后,将四个缓存区连接起来,组成128bit长度的MD5摘要,即为密文。
//生成MD5摘要
function md5($str){
$padding_str = padding($str);
$chunk = strlen($padding_str) / 64; //分段
for($i=0; $i<$chunk; $i++){
$str_chunk = substr($padding_str, $i*64, 64); //得到每一段字符串
$word = array();
for($j=0; $j<16; $j++){
$word[] = unpack("V", substr($str_chunk, $j*4, 4))[1]; //将字符串分为16组,每组4个字节,然后将每组转换成unsigned int数值
}
//四轮迭代
$s = array(7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21);
$K = array(0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391);
for($j=0; $j<64; $j++){
if($j<16){
md5_loop('F', $word[$j], $s, $j);
}
else if($j<32){
md5_loop('G', $word[(5*$j+1)%16], $s, $j);
}
else if($j<48){
md5_loop('H', $word[(3*$j+5)%16], $s, $j);
}
else{
md5_loop('I', $word[(7*$j)%16], $s, $j);
}
}
}
$md5_str = pack("V4", $A, $B, $C, $D); //将4个缓存区合并成字符串
return bin2hex($md5_str); //将字符串转换成16进制数值
}
三、MD5解密
MD5加密是一种单向加密算法,无法通过密文还原明文。但是可以通过穷举法,对所有可能的明文进行加密,找到和密文一致的密文,即为原来的明文。
//MD5解密
function md5_decrypt($str, $target_md5_str){
$padding_str = padding($str);
$chunk = strlen($padding_str) / 64;
for($i=0; $i<$chunk; $i++){
$str_chunk = substr($padding_str, $i*64, 64); //得到每一段字符串
$word = array();
for($j=0; $j<16; $j++){
$word[] = unpack("V", substr($str_chunk, $j*4, 4))[1]; //将字符串分为16组,每组4个字节,然后将每组转换成unsigned int数值
}
//四轮迭代
$s = array(7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21);
$K = array(0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd