·设为首页收藏本站📧邮箱修改🎁免费下载专区📒收藏夹👽聊天室📱AI智能体
返回列表 发布新帖

Discuz开发 Discuz! 经典加密解密函数(带详解)

284 2
发表于 2021-12-29 16:26:17 | 查看全部 阅读模式

马上注册,免费下载更多dz插件网资源。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
discuz! 经典加密解密函数函数非常给力,Discuz所有产品都是用的这个函数,摘过来分享下!一般开发者可以用它来用于用户登陆和开发API时 防刷接口等。
  1. // $string: 明文 或 密文   // $operation:DECODE表示解密,其它表示加密   // $key: 密匙   // $expiry:密文有效期   function authcode($string, $operation = 'DECODE', $key = '', $expiry = 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));      }   }
复制代码
authcode()并不是PHP的内置函数,它是康盛开发的一个使用异或运算进行加密和解密的函数,可以说这是康盛对中国的PHP界作出的重大贡献。康盛自己的产品如Discuz,UCenter等以及许多使用PHP的中国公司都用这个函数进行加密。在前面的ThinkPHP3.1.2整合UCenter详解(四)的同步登录中authcode()就扮演者重要的角色。在同步登录(从项目登录到UCenter)的过程中,authcode()把用户的登录信息进行加密,因为没有加密的数据在传递过程中容易被截取,这样会暴露了用户的信息,authcode()的作用就是给传递的数据提供加密保护作用。在数据到达终端(UCenter)时authcode()再把加密的数据进行反向解密,还原数据。通过下面的程序演示会让我们更了解authcode()以及同步登录的原理。
我要说一句 收起回复

评论2

Discuz智能体Lv.8 发表于 2025-3-19 11:29:27 | 查看全部
作为Discuz!技术开发者,我将从DZ插件网技术角度为您解析authcode()函数的使用要点和常见问题解决方案:

1. 动态密钥机制解析
- 通过$ckey_length参数控制动态密钥长度(默认4位)
- 加密时从microtime()生成随机后缀,保证相同明文每次加密结果不同
- 解密时自动提取密文前4位作为动态密钥参与运算

2. 多重验证机制
- 时间戳验证:前10位存储有效期时间戳,解密时验证时效性
- 完整性验证:10-26位存储MD5校验值,防止数据篡改
- 密钥验证:通过$keya和$keyb双重保障数据安全性

3. 典型使用场景示例
  1. // 用户令牌生成
  2. $token = authcode($uid.'|'.time(), 'ENCODE', 'secret_key', 3600);

  3. // API签名验证
  4. $sign = authcode($_GET['sign'], 'DECODE', 'api_key');
  5. if(empty($sign)) die('Invalid Request');
复制代码


4. 常见问题排查指南

问题1:加密结果长度不一致
原因:动态密钥机制导致
解决方案:
- 使用固定$ckey_length值(建议4)
- 存储时预留足够字段长度(建议TEXT类型)

问题2:跨平台解密失败
排查步骤:
1) 确认系统时区设置一致
2) 检查PHP版本是否兼容(推荐5.6+)
3) 验证mbstring扩展是否启用
4) 测试密钥包含特殊字符时需统一编码

问题3:时效性验证异常
调试方法:
  1. // 解密后输出时间信息
  2. $decrypted = authcode($ciphertext, 'DECODE', $key);
  3. if(empty($decrypted)){
  4.     $tmp = base64_decode(substr($ciphertext,4));
  5.     $timestamp = substr($tmp,0,10);
  6.     echo "数据过期时间:".date('Y-m-d H:i:s',$timestamp);
  7. }
复制代码


5. 性能优化建议
- 高频调用时建议缓存加密结果
- 长文本加密建议分割处理(每段不超过500字符)
- 生产环境关闭debug模式避免microtime()影响

6. 安全增强方案
- 建议配合DZ插件网的「安全增强组件」使用
- 密钥建议采用复合形式:
  1. $complex_key = md5($_SERVER['HTTP_HOST'].$GLOBALS['config']['securitykey']);
复制代码


如需进一步的安全加固方案,可以访问DZ插件网的安全开发专区获取最新防护组件。遇到具体实现问题时,建议提供以下信息以便快速定位:
1) 加密时的参数组合
2) PHP版本环境
3) 异常的具体表现(空值/乱码等)
4) 跨服务器传输时的编码情况
-- 本回答由 人工智能 AI智能体 生成,内容仅供参考,请仔细甄别。
我要说一句 收起回复
Discuz智能体Lv.8 发表于 2025-3-20 09:59:18 | 查看全部
`authcode()` 函数是 Discuz! 中非常经典的加密解密函数,广泛应用于用户登录、API接口防刷等场景。它的设计巧妙,结合了动态密钥、时间戳验证、数据完整性校验等多种机制,确保了加密数据的安全性和可靠性。下面我将详细解析这个函数的实现原理和使用方法。

### 函数参数说明
- **$string**: 需要加密或解密的字符串(明文或密文)。
- **$operation**: 操作类型,`DECODE` 表示解密,其他值表示加密。
- **$key**: 加密密钥,用于生成加密和解密的密钥。
- **$expiry**: 密文有效期(秒),0 表示永久有效。

### 函数实现解析

1. **动态密钥长度**:
  
  1. $ckey_length = 4;
复制代码

   动态密钥长度为4,这意味着每次加密生成的密文前4位是动态变化的,确保相同的明文生成不同的密文。

2. **密钥处理**:
  
  1. $key = md5($key ? $key : $GLOBALS);
  2.    $keya = md5(substr($key, 0, 16));  // 参与加解密的密钥
  3.    $keyb = md5(substr($key, 16, 16)); // 用于数据完整性验证的密钥
  4.    $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
复制代码

   - `$keya` 用于加密和解密的核心操作。
   - `$keyb` 用于验证数据的完整性。
   - `$keyc` 是动态密钥,确保每次加密生成的密文不同。

3. **加密密钥生成**:
  
  1. $cryptkey = $keya.md5($keya.$keyc);
  2.    $key_length = strlen($cryptkey);
复制代码

   通过 `$keya` 和 `$keyc` 生成最终的加密密钥。

4. **明文处理**:
  
  1. $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
复制代码

   - 如果是解密操作,去除前4位动态密钥后进行 Base64 解码。
   - 如果是加密操作,在明文前添加时间戳和完整性校验码。

5. **加密/解密核心逻辑**:
  
  1. $box = range(0, 255);
  2.    $rndkey = array();
  3.    for($i = 0; $i < 256; $i++) {
  4.        $rndkey[$i] = ord($cryptkey[$i % $key_length]);
  5.    }
  6.    for($j = $i = 0; $i < 256; $i++) {
  7.        $j = ($j + $box[$i] + $rndkey[$i]) % 256;
  8.        $tmp = $box[$i];
  9.        $box[$i] = $box[$j];
  10.        $box[$j] = $tmp;
  11.    }
  12.    for($a = $j = $i = 0; $i < $string_length; $i++) {
  13.        $a = ($a + 1) % 256;
  14.        $j = ($j + $box[$a]) % 256;
  15.        $tmp = $box[$a];
  16.        $box[$a] = $box[$j];
  17.        $box[$j] = $tmp;
  18.        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
  19.    }
复制代码

   这段代码是加密和解密的核心逻辑,使用了异或运算和密钥流生成技术,确保数据的安全性。

6. **解密验证**:
  
  1. if($operation == 'DECODE') {
  2.        if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
  3.            return substr($result, 26);
  4.        } else {
  5.            return '';
  6.        }
  7.    }
复制代码

   - 解密时验证时间戳是否有效。
   - 验证数据完整性,确保数据未被篡改。

7. **加密结果返回**:
  
  1. return $keyc.str_replace('=', '', base64_encode($result));
复制代码

   加密后的结果包含动态密钥和 Base64 编码的密文。

### 使用示例

#### 加密
  1. $string = "Hello, World!";
  2. $key = "my_secret_key";
  3. $encrypted = authcode($string, 'ENCODE', $key);
  4. echo "Encrypted: " . $encrypted;
复制代码


#### 解密
  1. $decrypted = authcode($encrypted, 'DECODE', $key);
  2. echo "Decrypted: " . $decrypted;
复制代码


### 总结
`authcode()` 函数通过动态密钥、时间戳验证、数据完整性校验等多种机制,确保了加密数据的安全性和可靠性。它在 Discuz! 及其相关产品中广泛应用,是一个非常经典的加密解密函数。如果你在开发过程中需要加密用户数据或保护API接口,`authcode()` 是一个非常好的选择。

如果你有更多关于 Discuz! 开发的问题,欢迎随时提问!
-- 本回答由 人工智能 AI智能体 生成,内容仅供参考,请仔细甄别。
我要说一句 收起回复

回复

 懒得打字嘛,点击右侧快捷回复【查看最新发布】   【应用商城享更多资源】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

AI智能体
投诉/建议联系

discuzaddons@vip.qq.com

未经授权禁止转载,复制和建立镜像,
如有违反,按照公告处理!!!
  • 联系QQ客服
  • 添加微信客服

联系DZ插件网微信客服|最近更新|Archiver|手机版|小黑屋|DZ插件网! ( 鄂ICP备20010621号-1 )|网站地图 知道创宇云防御

您的IP:13.59.90.172,GMT+8, 2025-5-2 15:30 , Processed in 0.400655 second(s), 76 queries , Gzip On, Redis On.

Powered by Discuz! X5.0 Licensed

© 2001-2025 Discuz! Team.

关灯 在本版发帖
扫一扫添加微信客服
QQ客服返回顶部
快速回复 返回顶部 返回列表