PHP实现数据加密与解密的两种常用方法分析
在PHP应用开发中,保障用户隐私与数据安全至关重要。本文将详细讲解两种主流的PHP加密解密技术方案:一是基于经典mcrypt扩展的对称加密流程,二是利用哈希运算、压缩算法与异或逻辑构建的高效自定义加解密函数。通过具体代码示例,揭示参数配置与执行步骤,助力开发者提升系统安全防护能力。
结果与目标
本实践旨在实现可逆的字符串加密功能,确保原始信息经过处理后变为不可读的密文,并能通过特定密钥准确还原。方案需兼顾实现的便捷性与一定程度的安全性,防止明文直接暴露于网络传输或数据库存储中。
准备条件
- 已安装支持
mcrypt扩展的 PHP 运行环境(注:mcrypt已在 PHP 7.2+ 中废弃,但作为原理学习仍有价值)。 - 基础 PHP 语法知识,熟悉字符串处理与二进制操作。
- 目标服务器需开启
mbstring等核心扩展以支持常规函数调用。
真实操作顺序
第1步:使用 mcrypt 扩展实现 DES 加密解密
目的:利用标准的 DES 对称加密算法,演示从模块初始化到数据加解密的标准闭环流程。
入口:定义两个独立函数 string2secret(加密)和 secret2string(解密)。
动作:
- 参数设置:设定固定密钥
$key = "123"。 - 模块初始化:调用
mcrypt_module_open(MCRYPT_DES, '', 'ecb', '')打开 DES 加密模块,ECB 模式无需 IV,但代码中仍生成了随机 IV 以备兼容或扩展。 - 密钥处理:获取密钥大小
$ks,并通过substr(md5($key), 0, $ks)截取 MD5 值的前部分作为实际使用的密钥,确保密钥长度符合算法要求。 - 执行加解密:使用
mcrypt_generic_init初始化加密资源,调用mcrypt_generic进行加密或mdecrypt_generic进行解密。 - 资源清理:解密后需使用
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)。
动作:
- 输入校验:检查
$string和$key是否有效,否则返回false。 - 密钥派生:
- 若为加密(
$isEncrypt = true),生成一个动态密钥$dynKey,基于当前微时间戳的 SHA1 哈希值。 - 无论加密与否,都使用传入的
$key生成固定密钥$fixedKey。
- 若为加密(
- 密钥重组:将动态密钥和固定密钥各分为前后两部分(各20位),交叉拼接后再次进行 SHA1 哈希,生成最终的混合密钥(40位)。这种设计增加了破解难度,因为动态部分随每次加密变化。
- 数据处理:
- 加密时:将动态密钥的一部分(前20位)拼接到原文前,对原文进行 Gzip 压缩(仅当长度超过300字节以节省空间)或 Base64 编码,最后再拼上动态密钥的另一部分。
- 解密时:提取密文中间的有效负载部分,先尝试 Base64 解码,若检测到压缩标志(长度判断),则进行反解压,否则仅解码。
- 异或运算:将处理后的字符串与混合密钥进行逐字符异或(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开发安全的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













