openssl_encrypt()和openssl_decrypt()是php对系统openssl c库的封装,非php自研;加密结果与命令行openssl enc等完全一致,需严格匹配算法、iv、密钥及openssl_raw_data等选项。

openssl_encrypt() 底层用的是 OpenSSL 库,不是 PHP 自己实现的
PHP 的 openssl_encrypt() 和 openssl_decrypt() 本质是调用系统级 OpenSSL C 库(比如 libcrypto),不是 PHP 解释器自己写的一套加解密逻辑。这意味着:加密结果和命令行 openssl enc、或 Python 的 cryptography 库在相同参数下完全一致——只要算法、模式、填充、IV、密钥都对得上。
常见误区是以为“PHP 加密函数 = PHP 自研”,其实它只是封装层。所以调试时可以直接用命令行验证:
echo "hello" | openssl enc -aes-256-cbc -K 0000...(32字节hex) -iv 0000...(16字节hex) -nopad -base64
结果应和 openssl_encrypt('hello', 'aes-256-cbc', hex2bin($key), 0, hex2bin($iv)) 一致。
AES-256-CBC 模式下,IV 和密钥必须严格匹配
CBC 模式要求每次加密都用新 IV,且解密时必须用**完全相同的 IV**,否则解密失败或得到乱码。IV 不需要保密,但绝不能复用——同一密钥 + 同一 IV 加密两个不同明文,会暴露前缀相似性。
-
openssl_cipher_iv_length('aes-256-cbc')固定返回16,必须用random_bytes(16)或openssl_random_pseudo_bytes(16)生成 - 密钥长度必须匹配算法:AES-256 要 32 字节(不是 32 个字符),
mb_strlen($key, '8bit') === 32才安全 - 如果密钥是字符串(比如用户输入的密码),必须用
hash('sha256', $password, true)衍生为二进制密钥,不能直接当密钥用
OPENSSL_RAW_DATA 是关键选项,不设就解不开
openssl_encrypt() 默认返回二进制原始数据(含不可见控制字符),直接 echo 会乱码或截断;而 openssl_decrypt() 默认也期望原始数据。如果加密后做了 base64_encode(),解密前必须先 base64_decode(),否则必然失败。
典型错误链:
- 加密用了
base64_encode($ciphertext),但解密时忘了base64_decode() - 加密时漏传
OPENSSL_RAW_DATA(即用默认值0),解密时却传了OPENSSL_RAW_DATA→ 格式不匹配 - 加密传了
OPENSSL_ZERO_PADDING,但解密没传,或反之 → 填充不一致导致解密失败
PHP 7.2+ 已彻底移除 mcrypt,别再查 mcrypt_* 函数
mcrypt 是 PHP 5 时代的遗留扩展,存在已知漏洞(如 ECB 模式无 IV、不支持 AEAD),且从 PHP 7.2 开始被完全移除。所有新项目必须用 openssl_* 或 sodium_*(推荐后者用于新场景)。
如果你看到文档或旧代码还在用 mcrypt_encrypt(),说明它至少落后 8 年以上,要么升级环境,要么重写加密逻辑——没有中间路线。
真正容易被忽略的点是:OpenSSL 底层依赖系统 OpenSSL 版本(比如 OpenSSL 1.1.1 vs 3.0),某些新算法(如 AES-GCM)在旧版本里不可用,openssl_get_cipher_methods() 返回结果会不同,上线前务必在目标环境实测。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











