OpenSSL 1.1.1+需编译启用enable-sm2/enable-sm4才支持国密,系统默认版本通常不支持;PHP依赖OpenSSL,故同样受限,可行方案为调用支持国密的OpenSSL CLI或使用php-sm4、sm-crypt等纯PHP库。

SM2/SM4 在 OpenSSL 中的支持现状
OpenSSL 从 1.1.1 版本开始原生支持国密算法,但需编译时启用 enable-sm2 和 enable-sm4 选项。默认发行版(如 Ubuntu、CentOS 自带的 OpenSSL)通常未开启国密支持,直接调用 openssl sm2 或 openssl sm4 会报错 “Unknown cipher” 或 “Command not found”。PHP 的 openssl_* 函数底层依赖 OpenSSL 库,因此若 OpenSSL 不支持 SM2/SM4,PHP 也无法直接使用。
PHP 中实现 SM2 加解密的可行路径
目前 PHP 原生不提供 SM2/SM4 的专用函数,需结合 OpenSSL CLI 或扩展方案:
-
推荐方式:调用系统 OpenSSL CLI(需已编译支持国密)
确认可用后,用exec()或shell_exec()调用命令,例如生成 SM2 密钥对:openssl genpkey -algorithm SM2 -out sm2_key.pem -pkeyopt ec_param_enc:named_curve -
密钥格式转换关键点
国密 SM2 私钥常用 PEM 格式(含-----BEGIN PRIVATE KEY-----),但部分国密设备或 SDK 要求 DER 或纯 ASN.1 二进制;公钥常需提取为压缩形式(02/03 开头的 65 字节)或未压缩(04 开头的 130 字节)。可用命令转换:openssl pkey -in sm2_key.pem -pubout -outform der | xxd -p -c 256(导出十六进制公钥) -
注意私钥保护
SM2 私钥必须严格保密,避免明文写入日志或响应;建议用openssl pkey -in sm2_key.pem -noout -text验证密钥参数是否符合 GB/T 32918.1-2016(曲线为 sm2p256v1)
SM4 加解密与密钥/IV 处理要点
SM4 是分组密码(128 位块),支持 ECB/CBC/CTR 等模式,但国密标准推荐使用 CBC 模式并要求 IV 随机且不可复用:
-
CBC 模式加解密示例(CLI)
加密:openssl sm4 -e -in data.txt -out data.enc -K $(xxd -p -c 32 key.bin) -iv $(xxd -p -c 16 iv.bin)
解密:openssl sm4 -d -in data.enc -out data.dec -K ... -iv ... -
密钥与 IV 格式
SM4 密钥必须为 16 字节(128 位)二进制数据,不可用字符串直接当密钥(如 "123456" 不合法);IV 同样为 16 字节。PHP 中可用random_bytes(16)生成,并用bin2hex()转为十六进制传给 OpenSSL 命令 -
避免 ECB 模式
ECB 不安全,国密应用中禁止使用;若必须兼容旧系统,需明确知晓其风险(相同明文块产生相同密文块)
替代方案:使用纯 PHP 国密库(无 OpenSSL 依赖)
若无法控制 OpenSSL 编译环境,可采用成熟纯 PHP 实现:
立即学习“PHP免费学习笔记(深入)”;
- php-sm4(GitHub 上轻量库):支持 CBC/ECB,密钥/IV 输入为 16 字节字符串,返回二进制密文,适合简单场景
- sm-crypt(支持 SM2/SM3/SM4):提供 SM2 签名/验签、加密/解密,公私钥支持 PEM/DER/十六进制格式互转,内置 ASN.1 解析逻辑
- 注意事项:纯 PHP 实现性能低于 OpenSSL,高并发下需压测;SM2 解密依赖私钥,务必确保私钥在内存中不被泄露(禁用 var_dump、错误日志输出私钥)



















