今天和大家分享一下discuz的加密和解密算法
研究了一个星期了,
总结了这个
算法有三个特点
1,动态性,同一字符串每次加密的密文都不一样
2,时间性,可以自己加一个限期参数,以秒为单位
3,统一性,加密和解密都用同一个函数
大家可以想一想
要想每次加密后的密文都不一样,而密钥是同一个,那解密只有一个办法,
就是把解密的信息肯定放到密文上面,从而解密
就像你跟不同的人下棋,对手有很多个,如果你想赢,肯定跟不同的人下就用不同的棋
法,而至于用什么棋法,就要看你的对手是个什么样的人,有急躁的,粗心的,等等
第二时间有限性
这个大家肯定一眼就能看出来如果我判断一个缓存过期了没有
我可以通过它的创建时间和现在时间对比一下,用这个差值和
租期比较有没有过期,那肯定这个也要放在密文里面
第三的话统一性的
该函数就用到异或算法,比较简单
例如 明文是01,密钥是10,两个异或完之后密文就是11,
而密文再和密钥异或就可以得到明文,也就是01
而密文和明文异或之后就可以得到密钥10,是不是很神奇
连我自己都不相信,但事实上就是这样,其实计算机还有很多
这样类似的规律

function uc_authcode($string, $operation = 'DECODE', $key = '123', $expiry = 0) {

$ckey_length = 4;

$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) : substr(md5(microtime()), -$ckey_length)) : '';

$cryptkey = $keya . md5($keya . $keyc); //64
$key_length = strlen($cryptkey); //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);

$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;
}

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]));
*/
}

if ($operation == 'DECODE') {
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 '';
}
} else {
return $keyc . str_replace('=', '', base64_encode($result));
}
}

分析一下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这个函数写的太精彩啦
第一次写教程,不懂排版,请大家见谅

转载于:https://www.cnblogs.com/simonlu/archive/2012/05/20/2510970.html

白话 discuz加密解密算法,包你懂相关推荐

  1. 【Android 安全】DEX 加密 ( Java 工具开发 | 加密解密算法 API | 编译代理 Application 依赖库 | 解压依赖库 aar 文件 )

    文章目录 一.加密解密算法 API 二.编译代理 Application 依赖库 三.解压代理 Application 依赖库 aar 文件 参考博客 : [Android 安全]DEX 加密 ( 常 ...

  2. 六个经典的PHP加密解密算法

    六个经典的PHP加密解密算法 六个经典的PHP加密解密算法 非常给力的authcode加密函数,Discuz!经典代码(带详解) 函数authcode($string, $operation, $ke ...

  3. C++实现古典密码-凯撒密码加密解密算法

    文章目录 第一部分 Caesar密码简介 1.1 基本思想 1.2 历史沿革 第二部分 Caesar密码的C++实现 第一部分 Caesar密码简介 1.1 基本思想 在密码学中,恺撒密码(英语:Ca ...

  4. java aes128加密解密_java AES 128 位加密解密算法

    最近在做app后台的服务器,使用到AES加密解密算法,无奈网上的都不符合要求,于是自己借鉴着写了一个AES加密解密工具. 密钥长度问题 默认 Java 中仅支持 128 位密钥,当使用 256 位密钥 ...

  5. 提供一个基于.NET的加密/解密算法

    提供一个基于.NET SymmetricAlgorithm 类的.带私钥的加密/解密算法的包装类.使用方法: symmcrypto de = new SymmCrypto(SymmCrypto.Sym ...

  6. C#的加密解密算法,包括Silverlight的MD5算法

    C#的加密解密算法,包括Silverlight的MD5算法 下面是一段加密解密工具类,其中的WinFormMD5Encrypt方法可以使得Winform和WebForm下的MD5加密结果一致,默认他们 ...

  7. php xxtea加密,PHP实现的XXTEA加密解密算法示例

    本文实例讲述了PHP实现的XXTEA加密解密算法.分享给大家供大家参考,具体如下: /** * Xxtea 加密实现类 */ class xxtea { private function long2s ...

  8. java 实现 DES加密 解密算法

    DES算法的入口参数有三个:Key.Data.Mode.其中Key为8个字节共64位,是DES算法的工作密钥:Data也为8个字节64位,是要被加密或被解密的数据:Mode为DES的工作方式,有两种: ...

  9. 基于新唐M0的XXTEA加密解密算法源码

    源:基于新唐M0的XXTEA加密解密算法源码 /*--------------------------------------------------------------------------- ...

最新文章

  1. android adb install Failure,提示base.apkcode is missing问题的解决
  2. 【数理知识】Riccati 黎卡提 system
  3. T-SQL 2 Tips: 1.计算任意两日期之间的周一到周日分别各有几个! 2.根据出生日期计算精确年龄!...
  4. 影响线型缩聚物分子量的因素_运城专业超高分子量聚乙烯油井内衬管生产基地...
  5. matplotlib之plot,figure(笔记一)
  6. 照片解锁手机不能忍?教你用OpenCV做活体检测 | 有代码
  7. Tensorflow——构造神经网络
  8. 100 以内的数的研究
  9. 使用wget下载GLDAS数据
  10. flashtool线刷工具
  11. 计算机软件销售适用增值税税率,计算机软件研发企业要交什么税,税率是多少...
  12. 天正建筑(TArch)8.0破解版下载(包含SP1、全系列注册机)
  13. 整数逆序输出, 例如输入一个整数12345,输出5 4 3 2 1
  14. 顾客细分(Customer Segmentation)(转载)
  15. Luogu P2656 采蘑菇
  16. 微信墙php_微信上墙PHP源码
  17. Allegro_理解通孔焊盘
  18. echarts 折线图高于目标显示绿色低于目标显示红色
  19. 【drawio笔记】向ERD表,列表和UML类添加行
  20. d3中文案例_D3.js实现动态仪表盘案列

热门文章

  1. 第八章:软件包的安装与管理
  2. 搜索引擎关键词劫持之php篇(源码与分析)
  3. DataGridView 中合并单元格
  4. 《SEO字典》解读meta robots标签
  5. 奥巴马:乔布斯改变我们每个人看世界的方式
  6. linux 自动安装系统,cobbler 自动安装linux系统
  7. linux touch 源码,每天一个Linux命令(09)--touch命令
  8. python多进程_Python多任务处理(多进程篇)
  9. cpu负载转移内存_为什么将所有工作负载转移到云中是个坏主意
  10. 谈论源码_当我们谈论开放音乐时,我们指的是什么?