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