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中使用反射技术的架构插件使用说明
May 18 PHP
用php解析html的实现代码
Aug 08 PHP
smarty巧妙处理iframe中内容页的代码
Mar 07 PHP
PHP笔记之:基于面向对象设计的详解
May 14 PHP
php随机显示图片的简单示例
Feb 15 PHP
Linux系统下使用XHProf和XHGui分析PHP运行性能
Dec 08 PHP
smarty中改进truncate使其支持中文的方法
May 30 PHP
彻底搞懂PHP 变量结构体
Oct 11 PHP
Laravel中服务提供者和门面模式的入门介绍
Nov 06 PHP
PHP让网站移动访问更加友好方法
Feb 14 PHP
Laravel 默认邮箱登录改成用户名登录的实现方法
Aug 12 PHP
laravel-admin 实现在指定的相册下添加照片
Oct 21 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
CodeIgniter基本配置详细介绍
2013/11/12 PHP
Drupal7中常用的数据库操作实例
2014/03/02 PHP
PHP连接MySQL的2种方法小结以及防止乱码
2014/03/11 PHP
php使用GD库创建图片缩略图的方法
2015/06/10 PHP
PHP中大括号'{}'用法实例总结
2017/02/08 PHP
php获取微信基础接口凭证Access_token
2018/08/23 PHP
PHP+redis实现的购物车单例类示例
2019/02/02 PHP
Gird事件机制初级读本
2007/03/10 Javascript
Javascript 变量作用域 两个可能会被忽略的小特性
2010/03/23 Javascript
再谈querySelector和querySelectorAll的区别与联系
2012/04/20 Javascript
innerText 使用示例
2014/01/23 Javascript
Flexigrid在IE下不显示数据的有效处理方法
2014/09/04 Javascript
js实现的全国省市二级联动下拉选择菜单完整实例
2015/08/17 Javascript
JavaScript File API实现文件上传预览
2016/02/02 Javascript
JavaScript入门系列之知识点总结
2016/03/24 Javascript
js插件dropload上拉下滑加载数据实例解析
2016/07/27 Javascript
BootStrap 动态添加验证项和取消验证项的实现方法
2016/09/28 Javascript
浅谈JavaScript的函数及作用域
2016/12/30 Javascript
浅谈箭头函数写法在ReactJs中的使用
2017/08/22 Javascript
微信小程序图片轮播组件gallery slider使用方法详解
2018/01/31 Javascript
Intellij IDEA搭建vue-cli项目的方法步骤
2018/10/20 Javascript
对 Vue-Router 进行单元测试的方法
2018/11/05 Javascript
详解服务端预渲染之Nuxt(介绍篇)
2019/04/07 Javascript
[03:49]辉夜杯现场龙骑士COSER秀情商“我喜欢芬队!”
2015/12/27 DOTA
使用Python计算玩彩票赢钱概率
2019/06/26 Python
Pytorch使用MNIST数据集实现CGAN和生成指定的数字方式
2020/01/10 Python
CSS3实现时间轴效果
2016/07/11 HTML / CSS
办公室经理岗位职责
2014/01/01 职场文书
运动会入场口号
2014/06/07 职场文书
应聘教师自荐书
2014/06/16 职场文书
行政执法作风整顿剖析材料
2014/10/11 职场文书
2015年副班长工作总结
2015/05/15 职场文书
给领导敬酒词
2015/08/12 职场文书
详解Js模块化的作用原理和方案
2021/04/29 Javascript
java executor包参数处理功能 
2022/02/15 Java/Android
使用 DataAnt 监控 Apache APISIX的原理解析
2022/07/07 Servers