Discuz教程网

[二次开发] 白话 discuz加密解密算法,包你懂

[复制链接]
authicon dly 发表于 2012-8-1 20:14:18 | 显示全部楼层 |阅读模式
今天和大家分享一下discuz的加密和解密算法
研究了一个星期了,
总结了这个
算法有三个特点
1,动态性,同一字符串每次加密的密文都不一样
2,时间性,可以自己加一个限期参数,以秒为单位
3,统一性,加密和解密都用同一个函数
大家可以想一想
第一 要想每次加密后的密文都不一样,而密钥是同一个,那解密只有一个办法,
就是把解密的信息肯定放到密文上面,从而解密
就像你跟不同的人下棋,对手有很多个,如果你想赢,肯定跟不同的人下就用不同的棋
法,而至于用什么棋法,就要看你的对手是个什么样的人,有急躁的,粗心的,等等
第二 时间有限性
这个大家肯定一眼就能看出来如果我判断一个缓存过期了没有
我可以通过它的创建时间和现在时间对比一下,用这个差值和
租期比较有没有过期,那肯定这个也要放在密文里面
第三 的话统一性的
该函数就用到异或算法,比较简单
例如 明文是01,密钥是10,两个异或完之后密文就是11,
而密文再和密钥异或就可以得到明文,也就是01
而密文和明文异或之后就可以得到密钥10,是不是很神奇
连我自己都不相信,但事实上就是这样,其实计算机还有很多
这样类似的规律
分析一下1到5行
就是简单的吧密钥用md5加密,没有密钥的话就用uckey
得到一串32个位加密后的密钥
$keya 作为密码本(就是一推打乱的数字)来用
$keyb参与加密这个跟密钥有关,解密用来验证的
$ckey_length = 4;
然后就是ckey_length的用处就是为了
就是限制一下加密的后的字符串长度
读者可以自己亲自试一下改变 ckey_length
看看输出来的密文一不一样
可以看看代码最后一句
return $keyc . str_replace('=', '', base64_encode($result));
下面分析keyc
请分析这一行
substr(md5(microtime()), -$ckey_length)) : '';
这就是为什么同一字符串加密后的密文都不一样
就是利用了时间的唯一性,上面是返回毫秒数再用Md5返回 0到32位的字符串给keyc
好接着分析
$cryptkey = $keya . md5($keya . $keyc); //64
$key_length = strlen($cryptkey); //64
这个 生成64位的密码本后面会用到
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string;
$string_length = strlen($string);
到这里啦
先不看解密的就是会执行这句
sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string;
// 明文,前10位用来保存时间戳,解密时验证数据有效性,10到26位用来保存$keyb的
如果没有租期的话前十位是0的
我们在这里可以得出
这时候的长度由
$ckey_length+10时间位+16位的$keyb+明文的长度
$result = '';
$box = range(0, 255);
$rndkey = array();
for ($i = 0; $i <= 255; $i++) { //字母表 64位后重复 数列 范围为48~122
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}

for ($j = $i = 0; $i < 256; $i++) { //这里是一个打乱算法
$j = ($j + $box[$i] + $rndkey[$i]) % 256;

$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
上面是生成256一个随机数组
就像洗牌算法一样
rand(0,52)
你可以循环52次来洗牌
如果重复的话再来一次rand
但这样的效率不高
而是用
for ($i = 0; $i < 52; $i++) {
$j = rand(0,52);
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
这样就算重复了随机数,但每个数在其他位置还是相等的概率,读者可以自己想一下
而上面 用了 $j = ($j + $box[$i] + $rndkey[$i]) % 256;
这句增加加了随机性,就是什么牌一样,第一个变了,其他也跟着变了,可以这样说吧
第一个数随机了,而后面的数也随机啦,而且随机性会越来愈大
不用rand(0,52)是为了保持加密和解密的密码本是一样的
for ($a = $j = $i = 0; $i < $string_length; $i++) {
$result .= chr(ord($string[$i]) ^ ($box[$i]));//先不要看这一句
/* $a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
*/
}
然后到了这里啦
其实上面也是打乱算法,再一次打乱,好像没什么用
但我自己想啊
如果把他注释掉
执行第一句
执行 后 也能加密也能机密,如果读者看懂的话告诉我一声,
后来想想可能是因为,我们第一次生成了0到255的随机数,而$string_length这个可能没有这么长
可能长度只有40,50啊,60啊,如果要加密的字符串很短的话,那密码本大于长度的那些元素就用不上
啦,那就浪费啦
我想可能是这个原因吧
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
这一句就是异或的作用啦,用ascci码异或后再转字符,函数可以自己查查是什么
比如 chr(ord('a')) 还是 a
return $keyc . str_replace('=', '', base64_encode($result));
最后来到这句
就完成了加密啦
为什么要用base64呢
呵呵,因为异或后的字符不一定是可以打印的字符,所以要用base64来加密一下,后面有时间我说一说
base64的原理和用Php亲自写一下
最后用keyc连接呵呵,还记得我开始说的话吗,慢慢理解一下
下面就开始分析解密的过程
上面讲过的那些就不讲啦
$key = md5($key ? $key : UC_KEY); //加密解密时这个是不变的
$keya = md5(substr($key, 0, 16)); //加密解密时这个是不变的
$keyb = md5(substr($key, 16, 16)); //加密解密时这个是不变的
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length) :
作用是为了保证加密和加密用的那个密码本是一样的
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length))
这里取出后$ckey_length个字符
10时间位+16位的$keyb+明文的长度
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
如果密码本加密和解密的一样 那么 这句就会变回明文啦,如果不清楚异或的看上面我介绍的
if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) {
return substr($result, 26);
} else {
return '';
}
好了,终于来到这里啦,先验证时间有效性,和KeyB是不是用这个密钥生成的,如果是就返回明文给他
Ok,终于分析完
其实我还有一个问题还没有明白就是为什么密码本长度是256个,我猜的话,因为ascii码两个相加不超过255
看看这句话$box[($box[$a] + $box[$j]) % 256],真的发觉discuz这个函数写的太精彩啦
第一次写教程,不懂排版,请大家见谅

?>




上一篇:Discuz的Memcache缓存实现
下一篇:ultraedit上实现php语法高亮、智能提示、编译和调试
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1314学习网 ( 浙ICP备10214163号 )

GMT+8, 2025-5-2 07:21

Powered by Discuz! X3.4

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表