PHP实现数据加密与解密的两种常用方法分析

南乔
南乔
发布时间:2026-10-13 | 5人浏览过
原创

在PHP应用开发中,保障用户隐私与数据安全至关重要。本文将详细讲解两种主流的PHP加密解密技术方案:一是基于经典mcrypt扩展的对称加密流程,二是利用哈希运算、压缩算法与异或逻辑构建的高效自定义加解密函数。通过具体代码示例,揭示参数配置与执行步骤,助力开发者提升系统安全防护能力。

结果与目标

本实践旨在实现可逆的字符串加密功能,确保原始信息经过处理后变为不可读的密文,并能通过特定密钥准确还原。方案需兼顾实现的便捷性与一定程度的安全性,防止明文直接暴露于网络传输或数据库存储中。

准备条件

  • 已安装支持 mcrypt 扩展的 PHP 运行环境(注:mcrypt 已在 PHP 7.2+ 中废弃,但作为原理学习仍有价值)。
  • 基础 PHP 语法知识,熟悉字符串处理与二进制操作。
  • 目标服务器需开启 mbstring 等核心扩展以支持常规函数调用。

真实操作顺序

第1步:使用 mcrypt 扩展实现 DES 加密解密

目的:利用标准的 DES 对称加密算法,演示从模块初始化到数据加解密的标准闭环流程。

入口:定义两个独立函数 string2secret(加密)和 secret2string(解密)。

动作:

  1. 参数设置:设定固定密钥 $key = "123"。
  2. 模块初始化:调用 mcrypt_module_open(MCRYPT_DES, '', 'ecb', '') 打开 DES 加密模块,ECB 模式无需 IV,但代码中仍生成了随机 IV 以备兼容或扩展。
  3. 密钥处理:获取密钥大小 $ks,并通过 substr(md5($key), 0, $ks) 截取 MD5 值的前部分作为实际使用的密钥,确保密钥长度符合算法要求。
  4. 执行加解密:使用 mcrypt_generic_init 初始化加密资源,调用 mcrypt_generic 进行加密或 mdecrypt_generic 进行解密。
  5. 资源清理:解密后需使用 trim() 去除填充字符,并调用 mcrypt_generic_deinit 和 mcrypt_module_close 释放内存资源。
//加密函数
function string2secret($str) {
    $key = "123";
    // 打开加密模块:算法 DES,模式 ECB
    $td = mcrypt_module_open(MCRYPT_DES, '', 'ecb', '');
    // 生成随机 IV(虽然ECB不需要,但为了完整性保留)
    $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
    // 获取密钥大小并截断密钥
    $ks = mcrypt_enc_get_key_size($td);
    $key = substr(md5($key), 0, $ks);
    
    // 初始化加密环境
    mcrypt_generic_init($td, $key, $iv);
    // 执行加密
    $secret = mcrypt_generic($td, $str);
    
    // 清理与关闭
    mcrypt_generic_deinit($td);
    mcrypt_module_close($td);
    return $secret;
}

//解密函数
function secret2string($sec) {
    $key = "123";
    $td = mcrypt_module_open(MCRYPT_DES, '', 'ecb', '');
    $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
    $ks = mcrypt_enc_get_key_size($td);
    $key = substr(md5($key), 0, $ks);
    
    mcrypt_generic_init($td, $key, $iv);
    // 执行解密
    $string = mdecrypt_generic($td, $sec);
    
    mcrypt_generic_deinit($td);
    mcrypt_module_close($td);
    // 去除末尾可能的填充符
    return trim($string);
}

// 测试调用
echo secret2string(string2secret("11111111111111111"));
// 输出: 11111111111111111
echo '<br>'.string2secret("11111111111111111");
// 输出: 乱码(密文)

第2步:构建基于哈希与异或的高性能加解密函数

目的:在不依赖外部复杂算法库的情况下,通过组合 SHA1、Base64、Gzip 压缩和异或运算,实现一种紧凑且具有一定混淆效果的加密方式。

入口:定义统一入口函数 dencrypt($string, $isEncrypt, $key)。

动作:

  1. 输入校验:检查 $string 和 $key 是否有效,否则返回 false。
  2. 密钥派生:
    • 若为加密($isEncrypt = true),生成一个动态密钥 $dynKey,基于当前微时间戳的 SHA1 哈希值。
    • 无论加密与否,都使用传入的 $key 生成固定密钥 $fixedKey。
  3. 密钥重组:将动态密钥和固定密钥各分为前后两部分(各20位),交叉拼接后再次进行 SHA1 哈希,生成最终的混合密钥(40位)。这种设计增加了破解难度,因为动态部分随每次加密变化。
  4. 数据处理:
    • 加密时:将动态密钥的一部分(前20位)拼接到原文前,对原文进行 Gzip 压缩(仅当长度超过300字节以节省空间)或 Base64 编码,最后再拼上动态密钥的另一部分。
    • 解密时:提取密文中间的有效负载部分,先尝试 Base64 解码,若检测到压缩标志(长度判断),则进行反解压,否则仅解码。
  5. 异或运算:将处理后的字符串与混合密钥进行逐字符异或(XOR)操作。由于异或的特性,同一密钥下再次异或即可恢复原文。
// 通用加解密函数
// $string: 要处理的字符串
// $isEncrypt: true=加密, false=解密
// $key: 私钥
function dencrypt($string, $isEncrypt = true, $key = "KEY_SPACE") {
    if (!isset($string{0}) || !isset($key{0})) {
        return false;
    }

    // 1. 生成动态部分(加密时基于时间戳,解密时不再生成此步的逻辑由后续提取决定,此处简化理解:加密产生新密钥片段)
    $dynKey = $isEncrypt ? hash('sha1', microtime(true)) : '';
    // 固定密钥基于私钥
    $fixedKey = hash('sha1', $key);

    // 2. 拆分密钥块
    $dynKeyPart1 = substr($dynKey, 0, 20);
    $dynKeyPart2 = substr($dynKey, 20);
    $fixedKeyPart1 = substr($fixedKey, 0, 20);
    $fixedKeyPart2 = substr($fixedKey, 20);

    // 3. 生成最终混合密钥
    // 注意:如果是解密,$dynKey为空,上述逻辑需要根据原文结构重构密钥。
    // 原版代码逻辑在解密时直接从密文中提取部分作为dynKey来源,这里保持原逻辑一致性说明:
    // 原代码在解密时并没有重新计算dynKey,而是利用密文结构反推。但在本例简化版中,我们关注其核心混合逻辑。
    
    $keyMix = hash('sha1', $dynKeyPart1 . $fixedKeyPart1 . $dynKeyPart2 . $fixedKeyPart2);

    // 4. 数据预处理(加密 vs 解密)
    if ($isEncrypt) {
        // 加密:添加动态前缀 -> 压缩/Base64 -> 添加动态后缀
        // 这里为了演示清晰,简化了原版复杂的动态密钥嵌入逻辑,仅保留核心思想:
        // 实际原版代码:$string = $fixedKeyPart1 . $string . $dynKeyPart2 ... 之后进行异或
        // 下面展示原版核心循环逻辑:
        $finalString = $fixedKeyPart1 . $string . $dynKeyPart2;
    } else {
        // 解密:原版逻辑较复杂,涉及从密文中提取dynKey来重建keyMix
        // 这里主要展示异或操作的通用性
        $finalString = $string;
    }

    // 5. 异或编码/解码
    // 核心算法:chr(ord(char) ^ ord(key_char))
    $result = '';
    $len = strlen($finalString); // 实际原版中可能包含动态拼接后的完整串
    for ($n = 0; $n < $len; $n++) {
        $result .= chr(ord($finalString{$n}) ^ ord($keyMix{$n % 40}));
    }

    return $isEncrypt ? base64_encode($result) : $result;
}

// 简化的测试调用(示意)
// echo strlen(dencrypt("12345678912345"));

注:第二段代码源自常见开源工具包中的高效加解密实现,其优势在于通过动态密钥碎片化降低了彩虹表攻击的风险,并利用 Gzip 压缩减少了网络传输带宽。在实际工程中,建议优先使用 openssl_encrypt 等现代标准库以保证安全性。

完成判断

  • 验证加密:调用加密函数后,原始文本应变为一串看起来随机的乱码字符串(如 Hex 或 Base64 格式),且无法直观识别内容。
  • 验证解密:将加密后的密文及相同密钥传入解密函数,输出的字符串应与初始输入的字符串完全一致,包括空格和特殊字符。

简要总结

本文通过两个实例展示了 PHP 中数据保护的不同层级。第一种方法侧重于传统的对称加密标准,适合对兼容性有要求的场景;第二种方法则体现了算法组合的思维,通过动态密钥和异或运算实现了轻量级的数据混淆。开发者应根据具体安全需求选择合适的方案,并注意在移除 deprecated 扩展后转向更安全的 OpenSSL 解决方案。以上就是PHP加密解密实例分析的详细内容,更多关于PHP开发安全的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表