sm2密钥生成须用国密版openssl并配置sm2p256v1曲线;sm4加解密需openssl_cipher_sm4_cbc及严格16字节iv;yii需自定义加密组件,且底层依赖gmssl动态库支持。

SM2密钥生成必须用openssl_pkey_new()配国密配置
OpenSSL原生不支持SM2,得靠国密版OpenSSL(如GMSSL)编译时启用enable-sm2,PHP的openssl扩展才能识别sm2算法名。直接调openssl_pkey_new()默认走RSA,不加配置会静默失败或生成RSA密钥。
- 生成前必须用
openssl_conf_read_file()加载含sm2支持的openssl.cnf,或在openssl_pkey_new()参数中显式传入['curve_name' => 'sm2p256v1'] - 私钥导出要用
openssl_pkey_export(),不能用openssl_pkey_get_private()再get_resource_id()——后者返回的是资源句柄,不是PEM字符串 - Yii里存私钥别用
yii\helpers\BaseStringHelper::base64Encode()二次编码,SM2私钥PEM本身已含Base64,重复编码会导致解密失败
SM4加解密必须指定OPENSSL_CIPHER_SM4_CBC且IV长度严格16字节
PHP 8.1+才内置OPENSSL_CIPHER_SM4_CBC常量,低版本需手动定义为0x80001。SM4的CBC模式对IV要求比AES更硬性:必须恰好16字节,且不能复用——哪怕只差1字节,openssl_encrypt()也会返回false,错误信息是"iv length is incorrect"。
- 生成IV务必用
random_bytes(16),别用mt_rand()拼接,后者输出非二进制安全 - 加密后数据需和IV一起存储,推荐格式:
base64_encode($iv . $ciphertext),解密时substr($data, 0, 16)取IV,substr($data, 16)取密文 - Yii的
yii\security\CipherTool不识别SM4,别试图塞'cipher' => 'sm4-cbc'进去,会报"Unsupported cipher"
Yii中替换默认加密组件要重写encryptByKey()和decryptByKey()
Yii的yii\security\CryptHelper底层调openssl_encrypt(),但硬编码了AES-128-CBC,没法通过配置切SM4。必须继承并重写两个方法,且注意密钥处理逻辑——SM2签名验签用的是椭圆曲线密钥对,而SM4加解密用的是对称密钥,二者密钥格式、长度、用途完全不兼容。
- SM4对称密钥必须是16/24/32字节,用
hash_hmac('sm3', $password, $salt, true)派生比直接md5()更合规 - SM2签名时,私钥用于
openssl_sign(),但需指定OPENSSL_ALGO_SHA256而非OPENSSL_ALGO_SM3——国密版OpenSSL实际把SM3哈希内嵌在签名流程里,PHP层看不到单独的SM3算法标识 - 别在
config/web.php里全局替换'crypt' => ['class' => MySm4Crypt::class],Yii的密码哈希(如Yii::$app->security->generatePasswordHash())仍走bcrypt,和SM4无关
调试时openssl_error_string()返回空?先检查extension=openssl是否加载正确
国密算法报错经常不抛异常,openssl_encrypt()直接返回false,openssl_error_string()却没内容。这不是代码问题,大概率是PHP没连上国密版OpenSSL动态库。
- 运行
php -i | grep openssl,确认OpenSSL Library Version含GMSSL字样,不是OpenSSL 1.1.1这类标准版 - Linux下检查
ldd $(php-config --extension-dir)/openssl.so | grep ssl,输出应指向libssl.so.1.1-gm之类带-gm后缀的库 - Windows用户别用PHP官方二进制包,必须用GMSSL官网提供的PHP集成包,否则
OPENSSL_CIPHER_SM4_CBC常量根本不存在










