news 2026/5/21 15:19:27

PHP 应用的国密算法(SM2/SM3/SM4)集成

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PHP 应用的国密算法(SM2/SM3/SM4)集成
┌──────┬────────────┬─────────────┬──────────────────────────────────┐──────────────────────────────────────────────── │ 算法 │ 类型 │ 对标 │ 用途 │ ├──────┼────────────┼─────────────┼──────────────────────────────────┤──────────────────────────────────────────────── │ SM2 │ 非对称加密 │ RSA/ECDSA │ 数字签名、密钥交换、加密小数据 │ ├──────┼────────────┼─────────────┼──────────────────────────────────┤ │ SM3 │ 哈希 │ SHA-256│ 数据完整性校验、数字签名前的摘要 │ ├──────┼────────────┼─────────────┼──────────────────────────────────┤ │ SM4 │ 对称加密 │ AES-128│ 大数据加密、文件加密、传输加密 │ └──────┴────────────┴─────────────┴──────────────────────────────────┘ 实际项目里三个经常组合用:SM2 交换密钥 → SM4 加密数据 → SM3 校验完整性。---PHP 扩展选型 方案一:gmssl 扩展(推荐) GmSSL 是国内主流国密库,有官方 PHP 扩展。 # 先安装 GmSSL git clone https://github.com/guanzhi/GmSSL cd GmSSL&&mkdir build&&cd build cmake..&&make&&make install # 安装 PHP 扩展 pecl install gmssl;php.ini extension=gmssl 方案二:纯 PHP 实现(无需扩展) composer require tjfoc/gmsm # 不行,这是 Go 的 composer require idealo/php-sm-crypto # 纯PHP,性能差但无依赖 composer require furqansiddiqui/ecc-php 国内用得最多的纯 PHP 库: composer require lybc/phpgm 方案三:openssl 命令行调用 OpenSSL1.1.1+已支持国密,可以通过 exec 调用,但不推荐生产用。---SM3 哈希 最简单,先从这个开始。 使用 gmssl 扩展 classSM3{public staticfunctionhash(string $data):string{returngmssl_sm3($data);}public staticfunctionhmac(string $data,string $key):string{returngmssl_sm3_hmac($key,$data);}public staticfunctionverify(string $data,string $hash):bool{returnhash_equals(self::hash($data),$hash);}}使用纯 PHP 实现 use Lybc\PhpGm\Sm3;$hash=Sm3::hash('hello world');// 返回 64 位十六进制字符串// 用于替代 SHA256 做密码哈希$passwordHash=Sm3::hash($password.$salt);实际应用:替代 MD5/SHA1 做数据校验 classDataIntegrity{public staticfunctionsign(array $data,string $secret):string{ksort($data);$str=http_build_query($data).'&key='.$secret;returnstrtoupper(SM3::hash($str));}public staticfunctionverify(array $data,string $sign,string $secret):bool{returnhash_equals(self::sign($data,$secret),$sign);}}---SM4 对称加密 基本用法 use Lybc\PhpGm\Sm4;classSM4Cipher{private const KEY_LENGTH=16;// SM4 密钥固定 128 位 = 16 字节public staticfunctionencrypt(string $plaintext,string $key,string $iv=''):string{self::validateKey($key);if(empty($iv)){$iv=random_bytes(16);}$sm4=newSm4($key,'cbc');// CBC 模式$ciphertext=$sm4->encrypt($plaintext,$iv);// 将 IV 拼在密文前面,解密时取出returnbase64_encode($iv.$ciphertext);}public staticfunctiondecrypt(string $ciphertext,string $key):string{self::validateKey($key);$raw=base64_decode($ciphertext);$iv=substr($raw,0,16);$data=substr($raw,16);$sm4=newSm4($key,'cbc');return$sm4->decrypt($data,$iv);}private staticfunctionvalidateKey(string $key):void{if(strlen($key)!==self::KEY_LENGTH){thrownew\InvalidArgumentException('SM4 key must be 16 bytes');}}}使用 gmssl 扩展(性能更好) classSM4GmSSL{public staticfunctionencrypt(string $plaintext,string $key):string{$iv=random_bytes(GMSSL_SM4_BLOCK_SIZE);$ciphertext=gmssl_sm4_cbc_encrypt($key,$iv,$plaintext);returnbase64_encode($iv.$ciphertext);}public staticfunctiondecrypt(string $encoded,string $key):string{$raw=base64_decode($encoded);$iv=substr($raw,0,GMSSL_SM4_BLOCK_SIZE);$ciphertext=substr($raw,GMSSL_SM4_BLOCK_SIZE);returngmssl_sm4_cbc_decrypt($key,$iv,$ciphertext);}}实际应用:数据库敏感字段加密 classEncryptedModelextendsModel{// 需要加密存储的字段protected array $encryptable=['id_card','bank_card','phone'];private staticfunctiongetKey():string{returnconfig('app.sm4_key');// 16字节,从环境变量读}publicfunctionsetAttribute($key,$value):mixed{if(in_array($key,$this->encryptable)&&$value!==null){$value=SM4Cipher::encrypt($value,self::getKey());}returnparent::setAttribute($key,$value);}publicfunctiongetAttribute($key):mixed{$value=parent::getAttribute($key);if(in_array($key,$this->encryptable)&&$value!==null){returnSM4Cipher::decrypt($value,self::getKey());}return$value;}}---SM2 非对称加密 生成密钥对 use Lybc\PhpGm\Sm2;classSM2KeyPair{public staticfunctiongenerate():array{$sm2=newSm2();$keypair=$sm2->createKey();return['private_key'=>$keypair['private_key'],// 十六进制'public_key'=>$keypair['public_key'],// 十六进制,04开头];}public staticfunctionsaveToFiles(array $keypair,string $dir):void{file_put_contents($dir.'/sm2_private.key',$keypair['private_key']);file_put_contents($dir.'/sm2_public.key',$keypair['public_key']);chmod($dir.'/sm2_private.key',0600);}}加密与解密 classSM2Cipher{// SM2 加密(用公钥)public staticfunctionencrypt(string $plaintext,string $publicKey):string{$sm2=newSm2();$ciphertext=$sm2->encrypt($plaintext,$publicKey);returnbase64_encode($ciphertext);}// SM2 解密(用私钥)public staticfunctiondecrypt(string $ciphertext,string $privateKey):string{$sm2=newSm2();return$sm2->decrypt(base64_decode($ciphertext),$privateKey);}}数字签名 classSM2Signer{// 签名:私钥签,SM3 做摘要public staticfunctionsign(string $data,string $privateKey):string{$sm2=newSm2();$hash=SM3::hash($data);$signature=$sm2->sign($hash,$privateKey);returnbase64_encode($signature);}// 验签:公钥验public staticfunctionverify(string $data,string $signature,string $publicKey):bool{$sm2=newSm2();$hash=SM3::hash($data);return$sm2->verify($hash,base64_decode($signature),$publicKey);}}实际应用:接口请求签名 classApiSigner{public staticfunctionsignRequest(array $params,string $privateKey):array{ksort($params);$params['timestamp']=time();$params['nonce']=bin2hex(random_bytes(8));$signStr=http_build_query($params);$params['sign']=SM2Signer::sign($signStr,$privateKey);$params['sign_type']='SM2';return$params;}public staticfunctionverifyRequest(array $params,string $publicKey):bool{// 防重放:时间戳5分钟内有效if(abs(time()-$params['timestamp'])>300){returnfalse;}$sign=$params['sign'];unset($params['sign'],$params['sign_type']);ksort($params);$signStr=http_build_query($params);returnSM2Signer::verify($signStr,$sign,$publicKey);}}---三算法组合:信封加密 实际传输大数据时的标准做法: classSM2SM4Envelope{/** * 加密: * 1. 随机生成 SM4 密钥 * 2. SM4 加密数据 * 3. SM2 加密 SM4 密钥 * 4. SM3 对密文做完整性校验 */public staticfunctionseal(string $plaintext,string $sm2PublicKey):array{$sm4Key=random_bytes(16);$ciphertext=SM4Cipher::encrypt($plaintext,$sm4Key);$encryptedKey=SM2Cipher::encrypt(bin2hex($sm4Key),$sm2PublicKey);$mac=SM3::hmac($ciphertext,$sm4Key);return['encrypted_key'=>$encryptedKey,'ciphertext'=>$ciphertext,'mac'=>$mac,];}/** * 解密:反向操作 */public staticfunctionopen(array $envelope,string $sm2PrivateKey):string{$sm4KeyHex=SM2Cipher::decrypt($envelope['encrypted_key'],$sm2PrivateKey);$sm4Key=hex2bin($sm4KeyHex);// 验证完整性$expectedMac=SM3::hmac($envelope['ciphertext'],$sm4Key);if(!hash_equals($expectedMac,$envelope['mac'])){thrownew\RuntimeException('数据完整性校验失败');}returnSM4Cipher::decrypt($envelope['ciphertext'],$sm4Key);}}---与 HTTPS/TLS 的国密改造 如果需要 HTTPS 层也用国密(等保三级有时要求): # Nginx 需要编译 tongsuo 或 BabaSSL 支持 ssl_protocols TLSv1.2TLSv1.3;ssl_ciphers"ECC-SM2-SM4-CBC-SM3:ECDHE-SM2-SM4-CBC-SM3:...";ssl_certificate/path/to/sm2_cert.pem;ssl_certificate_key/path/to/sm2_key.pem;PHP 层不需要改动,TLS 握手在 Nginx 层完成。---常见坑 密钥长度 SM4 密钥必须是16字节,不能用字符串直接当密钥,要用hash('sm3',$password,true)派生后取前16字节。 编码问题 SM2 公钥有压缩(02/03开头)和非压缩(04开头)两种格式,不同库默认不同,互通时要确认格式一致。 C04 格式 部分政务系统要求 SM2 密文用 C1C3C2 顺序,而不是默认的 C1C2C3,对接时要问清楚。 性能 纯 PHP 实现的 SM2 很慢,签名一次约50-200ms,高并发场景必须用 gmssl 扩展或异步队列处理。---选型建议 ┌────────────────────┬─────────────────────────┐ │ 场景 │ 推荐方案 │ ├────────────────────┼─────────────────────────┤ │ 等保合规、政务对接 │ gmssl 扩展+硬件密码机 │ ├────────────────────┼─────────────────────────┤ │ 普通商业项目 │ 纯 PHP 库(lybc/phpgm) │ ├────────────────────┼─────────────────────────┤ │ 数据库字段加密 │ SM4 CBC 模式 │ ├────────────────────┼─────────────────────────┤ │ 接口签名 │ SM2+SM3 │ ├────────────────────┼─────────────────────────┤ │ 大文件传输加密 │ 信封加密(SM2+SM4+SM3) │ └────────────────────┴─────────────────────────┘
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/21 15:19:19

PHP 应用的水平扩展与会话共享方案

核心挑战:PHP 默认把 session 存在本地文件系统,水平扩展后请求可能落到不同节点,导致 session 丢失。 --- …

作者头像 李华
网站建设 2026/5/21 15:18:19

linux系统使用questa仿真microblaze

(1)Tools---Compile Simulation Labraries 将仿真库编译好。 (2)在vivado内搭建好BD (3)在vitis内写好c代码,生成elf文件 (4)将block design右键,Associate elf Files,可以只绑定到仿真。 (5)file---Export---Export Simulation 导出仿真脚本…

作者头像 李华
网站建设 2026/5/21 15:17:46

Powershell基础入门

学习大纲: PowerShell 基础语法与核心概念系统版本、环境与执行策略配置标准动词 & 常用核心命令入门阶段一:基础入门 1. 环境准备 官方学习地址:https://learn.microsoft.com 学习目标 掌握 PowerShell 基础语法、命令结构、核心概念&am…

作者头像 李华
网站建设 2026/5/21 15:17:26

【基础演练】Playwright 极简复习:作为 AI-RPA 底座的 Playwright 核心用法

一句话定调:2026 年的 Playwright 早已不是“又一个测试框架”——它在 npm 上以超过 3300 万的周下载量碾压所有对手,被 browser-use、Stagehand、Skyvern 等 AI Agent 项目集体选为默认浏览器引擎,同时微软官方推出的 Playwright MCP Server 让它成为大语言模型与真实网页…

作者头像 李华