discuz authcode 经典php加密解密函数解析


Posted in PHP onJuly 12, 2020

authcode()并不是PHP的内置函数,它是康盛开发的一个使用异或运算进行加密和解密的函数,可以说这是康盛对中国的PHP界作出的重大贡献。康盛自己的产品如Discuz,UCenter等以及许多使用PHP的中国公司都用这个函数进行加密。在前面的ThinkPHP3.1.2整合UCenter详解(四)的同步登录中authcode()就扮演者重要的角色。在同步登录(从项目登录到UCenter)的过程中,authcode()把用户的登录信息进行加密,因为没有加密的数据在传递过程中容易被截取,这样会暴露了用户的信息,authcode()的作用就是给传递的数据提供加密保护作用。在数据到达终端(UCenter)时authcode()再把加密的数据进行反向解密,还原数据。通过下面的程序演示会让我们更了解authcode()以及同步登录的原理。

discuz的 authcode 函数可以说对中国的PHP界作出了重大贡献。包括康盛自己的产品,以及大部分中国使用PHP的公司都用这个函数进行加密,authcode 是使用异或运算进行加密和解密。

原理如下,假如:

加密
明文:1010 1001
密匙:1110 0011
密文:0100 1010
得出密文0100 1010,解密之需和密匙异或下就可以了
解密
密文:0100 1010
密匙:1110 0011
明文:1010 1001
并没有什么高深的算法,密匙重要性很高,所以,关键在于怎么生成密匙。

那我们一起看下康盛的authcode怎么做的吧

// 参数解释
// $string: 明文 或 密文
// $operation:DECODE表示解密,其它表示加密
// $key: 密匙
// $expiry:密文有效期
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
    // 动态密匙长度,相同的明文会生成不同密文就是依靠动态密匙
    // 加入随机密钥,可以令密文无任何规律,即便是原文和密钥完全相同,加密结果也会每次不同,增大破解难度。
    // 取值越大,密文变动规律越大,密文变化 = 16 的 $ckey_length 次方
    // 当此值为 0 时,则不产生随机密钥
    $ckey_length = 4;
 
    // 密匙
    $key = md5($key ? $key : $GLOBALS['discuz_auth_key']);
 
    // 密匙a会参与加解密
    $keya = md5(substr($key, 0, 16));
    // 密匙b会用来做数据完整性验证
    $keyb = md5(substr($key, 16, 16));
    // 密匙c用于变化生成的密文
    $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
    // 参与运算的密匙
    $cryptkey = $keya.md5($keya.$keyc);
    $key_length = strlen($cryptkey);
    // 明文,前10位用来保存时间戳,解密时验证数据有效性,10到26位用来保存$keyb(密匙b),解密时会通过这个密匙验证数据完整性
    // 如果是解码的话,会从第$ckey_length位开始,因为密文前$ckey_length位保存 动态密匙,以保证解密正确
    $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++) {
        $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++) {
        $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') {
        // substr($result, 0, 10) == 0 验证数据有效性
        // substr($result, 0, 10) - time() > 0 验证数据有效性
        // substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16) 验证数据完整性
        // 验证数据有效性,请看未加密明文的格式
        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 {
        // 把动态密匙保存在密文里,这也是为什么同样的明文,生产不同密文后能解密的原因
        // 因为加密后的密文可能是一些特殊字符,复制过程可能会丢失,所以用base64编码
        return $keyc.str_replace('=', '', base64_encode($result));
    }
}

使用方法

$a = "3water.com";
$b = authcode($a, "ENCODE", "abc123");
echo $b."<br/>";
echo authcode($b, "DECODE", "abc123");

运行效果如下:

bf04VXLxyjHj2dS6UHYJvra/9Sm5irF/TBMHRMBtYejLTkUKQA
3water.com

注:因学习需要,转载挡笔记.文章来源于网络.

PHP 相关文章推荐
高亮度显示php源代码
Oct 09 PHP
我的群发邮件程序
Oct 09 PHP
isset和empty的区别
Jan 15 PHP
linux下为php添加curl扩展的方法
Jul 29 PHP
PHP逐行输出(ob_flush与flush的组合)
Feb 04 PHP
php动态生成函数示例
Mar 21 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(十一)
Jun 25 PHP
使用PHP和HTML5 FormData实现无刷新文件上传教程
Sep 06 PHP
PHP使用PDO连接ACCESS数据库
Mar 05 PHP
ThinkPHP文件缓存类代码分享
Apr 22 PHP
php基础教程
Aug 26 PHP
PHP常用header头定义代码示例汇总
Aug 29 PHP
php下使用SimpleXML 处理XML 文件
Feb 27 #PHP
PHP 导出数据到淘宝助手CSV的方法分享
Feb 27 #PHP
基于pear auth实现登录验证
Feb 26 #PHP
php str_pad() 将字符串填充成指定长度的字符串
Feb 23 #PHP
php 用checkbox一次性删除多条记录的方法
Feb 23 #PHP
PHP实现域名whois查询的代码(数据源万网、新网)
Feb 22 #PHP
PHP 伪静态隐藏传递参数名的四种方法
Feb 22 #PHP
You might like
加速XP搜索功能堪比vista
2007/03/22 PHP
PHP 文件扩展名 获取函数
2009/06/03 PHP
PHP列出MySQL中所有数据库的方法
2015/03/12 PHP
PHP-FPM之Chroot执行环境详解
2015/08/03 PHP
Yii2中hasOne、hasMany及多对多关联查询的用法详解
2017/02/15 PHP
JavaScript DOM 学习第九章 选取范围的介绍
2010/02/19 Javascript
javascript数组去掉重复
2011/05/12 Javascript
mailto的使用技巧分享
2012/12/21 Javascript
函数式 JavaScript(一)简介
2014/07/07 Javascript
jquery中键盘事件小结
2016/02/24 Javascript
网页前端登录js按Enter回车键实现登陆的两种方法
2016/05/10 Javascript
jQuery自定义图片缩放拖拽插件imageQ实现方法(附demo源码下载)
2016/05/27 Javascript
实例分析浏览器中“JavaScript解析器”的工作原理
2016/12/12 Javascript
详解NodeJs支付宝移动支付签名及验签
2017/01/06 NodeJs
nodejs动态创建二维码的方法
2017/08/12 NodeJs
vue项目打包后打开页面空白解决办法
2018/06/29 Javascript
vue实现图片懒加载的方法分析
2020/02/05 Javascript
Javascript实现打鼓效果
2021/01/29 Javascript
使用Django的模版来配合字符串翻译工作
2015/07/27 Python
python文件操作相关知识点总结整理
2016/02/22 Python
快速解决PyCharm无法引用matplotlib的问题
2018/05/24 Python
Selenium(Python web测试工具)基本用法详解
2018/08/10 Python
matplotlib绘制多个子图(subplot)的方法
2019/12/03 Python
使用python从三个角度解决josephus问题的方法
2020/03/27 Python
捷克家居装饰及图书音像购物网站:Velký košík
2018/04/16 全球购物
Levi’s西班牙官方网站:李维斯,著名的牛仔裤品牌
2020/08/20 全球购物
应届毕业生应聘自荐信
2013/12/07 职场文书
自行车租赁公司创业计划书
2014/01/28 职场文书
董事长助理工作职责
2014/06/08 职场文书
大二学生自我检讨书
2014/10/23 职场文书
学生上课迟到检讨书
2015/01/01 职场文书
大学生自荐信范文
2015/03/05 职场文书
刑事起诉书范文
2015/05/19 职场文书
2015年公司行政后勤工作总结
2015/05/20 职场文书
2015年大学迎新工作总结
2015/07/16 职场文书
在HTML5 localStorage中存储对象的示例代码
2021/04/21 Javascript