PHP如何解决使用国密SM4解密Base64数据错误问题?(基于lpilp/guomi)

最近遇到与java对接的时候接收的base64数据,SM4解密一部分正常、一部分乱码乱码的问题,最后仔细看了接收到的base64数据,发现是PHP接收url中的数据问题。

一、下面展示下解决问题之前的问题:

首先、把需要加密的json串整理出来,进行SM4加密

其次、将加密后的base64串添加到接口请求工具中data参数值中

再次、打印PHP接收到的base64数据串

最后、用接收到的数据串进行SM4解密,打印出来发现只解析了前面一点点,后面的是乱码

解决思路:

重点在以下几点:

1、接收到的base64数据;

2、lpilp/guomi扩展包中的SM4加密解密的方法;

思考:扩展包的加密解密方法肯定是没问题的,但是也不保证没有问题,细扒代码,发现是在解密base64_decode数据后,用解密方法解出来后就有问题了,解密方法之前用过,可以肯定没有问题,那就是传入的解密数据有问题了。

发现问题:仔细一看打印出来的加密后的数据和PHP接收到的数据不一样,接收到的数据中有空格。

原因是:+号在 URL 中被浏览器/前端自动转换成空格(空格编码成 %20),而后端 request()->all() 又把空格保留下来,最终造成 Base64 字符串被破坏。

解决办法:将接收到的数据中的空格转换成+号还原。再去调用解密方法

复制代码
$cipher = str_replace(' ', '+', $cipher);   // 把空格全部还原成 +
$plain  = (new RtSm4($key))->decrypt($cipher, 'sm4-ecb', '', 'base64');

将数据顺利解密,出来的结果如下:

与加密数据一致。

附件:SM4和SM2加密解密的公共调用方法

复制代码
<?php

namespace App\Support;
use Rtgm\sm\RtSm4;
use Rtgm\sm\RtSm2;
use Rtgm\util\MyAsn1;

class GuomiHelper
{
    /**
     * 生成安全随机数(不超过128位)
     *
     * @param int $length 随机数长度,最大128位
     * @return string
     */
    public static function generateNonce($length = 32)
    {
        $length = min($length, 128);
        $bytes = random_bytes(ceil($length / 2));
        return substr(bin2hex($bytes), 0, $length);
    }

    /**
     * 使用 key 进行 SM4 ECB 加密(在用)
     *
     * @param string $data
     * @param string $key
     * @return string
     */
    public static function sm4EcbEncrypt($data, $key) 
    {
        //dump($data);
        // 使用示例
        // $key = hex2bin("30ca0d013a9a782fe4c6b4c30d3e208c");
        // $data = "18900112233"; 运行结果;571d9decc557bd9d466f6c90df328bb4
        $key = hex2bin($key);//将十六进制字符串转换为二进制数据
        $sm4 = new RtSm4($key);
        $ciphertext = $sm4->encrypt($data, 'sm4-ecb','','base64');
        return $ciphertext;
    }
    /**
     * 使用 key 进行 SM4 ECB 解密(在用)
     * 
     * @param string $data
     * @param string $key
     * @return string
     */
    public static function sm4EcbDecrypt($data, $key) 
    {
        // 移除base64编码中的空格换行
        $key = hex2bin($key);//将十六进制字符串转换为二进制数据 $data, $type = 'sm4', $iv = '', $formatInput = 'hex'
        $sm4 = new RtSm4($key);
        $plaintext = $sm4->decrypt($data, 'sm4-ecb','','base64');
        return $plaintext;
    }

    /**
     * 账户公钥SM2加密(在用)
     *
     * @param string $data
     * @param string $publicKey
     * @return string
     */
    public static function rtSm2Encrypt($plaintext, $publicKeyBase64) 
    {    
        // 从DER格式中提取公钥内容(去除ASN.1头部)
        $publicKeyHex =  MyAsn1::decode($publicKeyBase64,'base64');
        // 创建SM2实例
        $sm2 = new RtSm2();
        // 执行加密(使用公钥的十六进制格式)
        $ciphertextBin = $sm2->doEncrypt($plaintext, $publicKeyHex[1]);
        return '04'.$ciphertextBin;
    }

    /**
     * 账户私钥SM2解密(在用)
     */
    public static function rtSm2Decrypt($ciphertext, $privateKey) {
         // 创建SM2实例
        $sm2 = new RtSm2();
        $m2DecryptData = $sm2->doDecrypt($ciphertext,$privateKey);
        return $m2DecryptData;
    }

    /**
     * 账户公钥SM2验签
     * 使用 SM2 非对称加密算法结合 SM3 哈希算法对给定的数据进行签名验证
     * @param string $publicKeyString:十六进制字符串表示的 SM2 公钥。
     * @param string $notifyString:需要验证签名的原始数据字符串。
     * @param string $signString:十六进制字符串表示的签名数据。
     * @return string
     */
    public static function sm2WithSM3Verify($publicKeyString, $notifyString, $signString)
    {
        $sm2 = new RtSm2();
        $result = $sm2->verifySign($notifyString, $signString, $publicKeyString);
        return $result;
    }
}
相关推荐
BingoGo2 小时前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php
JaguarJack2 小时前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php·服务端
JaguarJack1 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
后端·php·服务端
BingoGo1 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
php
JaguarJack2 天前
告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速
后端·php·laravel
郑州光合科技余经理3 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
feifeigo1233 天前
matlab画图工具
开发语言·matlab
dustcell.3 天前
haproxy七层代理
java·开发语言·前端
norlan_jame3 天前
C-PHY与D-PHY差异
c语言·开发语言
多恩Stone3 天前
【C++入门扫盲1】C++ 与 Python:类型、编译器/解释器与 CPU 的关系
开发语言·c++·人工智能·python·算法·3d·aigc