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 相关文章推荐
模仿OSO的论坛(一)
Oct 09 PHP
MySQL时间字段究竟使用INT还是DateTime的说明
Feb 27 PHP
php开启openssl的方法
May 15 PHP
thinkphp普通查询与表达式查询实例分析
Nov 24 PHP
PHP实现无限极分类图文教程
Nov 25 PHP
100多行PHP代码实现socks5代理服务器[2]
May 05 PHP
PHP面向对象程序设计高级特性详解(接口,继承,抽象类,析构,克隆等)
Dec 02 PHP
搜索附近的人PHP实现代码
Feb 11 PHP
php读取本地json文件的实例
Mar 07 PHP
php实现数组中出现次数超过一半的数字的统计方法
Oct 14 PHP
PHP中有关长整数的一些操作教程
Sep 11 PHP
PHP封装请求类实例分析【基于Yii框架】
Oct 17 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
Laravel数据库读写分离配置的方法
2019/10/13 PHP
基于thinkphp5框架实现微信小程序支付 退款 订单查询 退款查询操作
2020/08/17 PHP
Mootools 1.2教程 正则表达式
2009/09/15 Javascript
jquery.post用法示例代码
2014/01/03 Javascript
使用AngularJS 应用访问 Android 手机的图片库
2015/03/24 Javascript
jQuery实现平滑滚动页面到指定锚点链接的方法
2015/07/15 Javascript
jQuery实现默认是闭合的FAQ展开效果菜单
2015/09/14 Javascript
JS+CSS实现仿msn风格选项卡效果代码
2015/10/22 Javascript
实例解析jQuery插件EasyUI最常用的表单验证规则
2015/11/29 Javascript
js中的eval()函数把含有转义字符的字符串转换成Object对象的方法
2016/12/02 Javascript
微信小程序开发教程之增加mixin扩展
2017/08/09 Javascript
深入浅析Vue.js计算属性和侦听器
2018/05/05 Javascript
在Vue中用canvas实现二维码和图片合成海报的方法
2019/06/10 Javascript
npm的lock机制解析
2019/06/20 Javascript
vue router 跳转时打开新页面的示例方法
2019/07/28 Javascript
Auto.JS实现抖音刷宝等刷视频app,自动点赞,自动滑屏,自动切换视频功能
2020/05/08 Javascript
vue中解决chrome浏览器自动播放音频和MP3语音打包到线上的实现方法
2020/10/09 Javascript
使用graphics.py实现2048小游戏
2015/03/10 Python
详解详解Python中writelines()方法的使用
2015/05/25 Python
python生成九宫格图片
2018/11/19 Python
QML使用Python的函数过程解析
2019/09/26 Python
keras 多任务多loss实例
2020/06/22 Python
Python使用Selenium模拟浏览器自动操作功能
2020/09/08 Python
aec加密 php_php aes加密解密类(兼容php5、php7)
2021/03/14 PHP
世界各地的旅游、观光和活动:Isango!
2019/10/29 全球购物
世界上最好的野生海鲜和有机食品:Vital Choice
2020/01/16 全球购物
Linux的文件类型
2016/07/05 面试题
自我评价的正确写法
2013/09/19 职场文书
2014信息技术专业毕业生自我评价
2014/01/17 职场文书
小区停车场管理制度
2014/01/27 职场文书
小学生获奖感言范文
2014/02/02 职场文书
个人贷款承诺书
2014/03/28 职场文书
表彰大会策划方案
2014/05/13 职场文书
学校地质灾害防治方案
2014/06/10 职场文书
会议承办单位欢迎词
2015/09/30 职场文书
Java spring定时任务详解
2021/10/05 Java/Android