跳转到主内容
极星编程网:以代码为星,赴技术山海!

PHP实现数据加密传输_国密SM2SM4算法实战应用【说明】

SM4解密乱码或空字符串主因是填充不一致:PHP类默认PKCS#7填充,而GmSSL命令行默认不填充且要求明文16字节对齐,需两端严格统一填充方式,并确保CBC模式下iv相同且正确传递。
SM4
适合对称加密场景,
SM2
用于非对称密钥交换或签名验签——两者不能混用,选错直接导致解密失败或验签不过。 为什么
SM4
解密总是返回乱码或空字符串? 常见原因是填充(padding)不一致。PHP纯实现中,绝大多数
Sm4Helper
类默认使用PKCS#7填充,但如果你用
GmSSL
命令行加密(如
gmssl sm4 -encrypt
),它默认 不填充 ,且输入必须是16字节对齐的原始数据。 确保加解密两端填充方式完全一致:要么都开启PKCS#7,要么都禁用(需手动补零) 明文长度不是16倍数时,纯PHP类会自动填充;而
GmSSL
要求你提前处理:
str_pad($plaintext, (ceil(strlen($plaintext) / 16) * 16), "\0", STR_PAD_RIGHT)
ECB模式下尤其明显;CBC模式还需校验
iv
是否相同且传递正确
SM2
加密后前端/银行系统无法解密? 核心问题往往出在公钥格式和密文结构上。招商银行、银联等机构要求的
SM2
密文是“C1C3C2”拼接格式(即椭圆曲线点+杂凑值+密文),但很多PHP库(包括部分
lpilp/guomi
旧版)默认输出的是“C1C2C3”。 检查你调用的
doEncrypt()
方法返回值顺序,必要时手动重组:
$ciphertext = $c1 . $c3 . $c2
公钥传入前必须去除PEM头尾,并确认是否已转为无格式的
04 + x + y
格式(65字节);若银行提供的是PKCS#8 Base64串,要用
MyAsn1::decode()
或
openssl_pkey_get_public()
提取原始坐标 注意:部分银行接口要求密文Base64编码后再传输,别漏掉这步
SM4
该用 ECB 还是 CBC?生产环境怎么选? ECB模式简单,但 绝对不能用于生产 :相同明文块永远生成相同密文块,存在严重模式泄露风险(比如加密固定格式的身份证号,攻击者可轻易识别字段位置)。 PHP 8.5.5 PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。 下载 立即学习 “ PHP免费学习笔记(深入) ”; 生产必须用
CBC
或
CTR
模式,且
iv
必须随机生成、每次不同,并随密文一同传输(通常前置16字节)
lpilp/guomi
的
sm4_encrypt()
默认是ECB;要切CBC,得显式传参:
$cipher = new Sm4(); $cipher->setMode(Sm4::MODE_CBC); $cipher->setIv($iv);
若用
GmSSL
命令行,CBC需显式指定
-iv
参数,且
iv
必须是16字节十六进制字符串(如
000102030405060708090a0b0c0d0e0f
) 密钥管理比算法本身更易出问题:128位
SM4
密钥必须严格为16字节二进制数据,传入字符串时别忘了
hex2bin()
或
pack('H*', $keyHex)
;
SM2
私钥若从文件读取,确保没带换行或空格——这些细节一旦错,错误信息往往只报“decryption failed”,实际跟算法无关。

相关文章