技术饭

php的sm2加密、签名、验签,sm4加密

copylian    0 评论    11150 浏览    2023.09.05

php的sm2加密、签名、验签,sm4加密,为了保障商用密码的安全性,国家密码局制定了一系列密码标准,包括:SM1(SCB2)、SM2、SM3、SM4、SM7、SM9、祖冲之密码算法(ZUC) 等。其中SM1、SM4、SM7、祖冲之密码(ZUC)是对称算法。SM2、SM9是非对称算法。SM3是哈希算法,其中SM1、SM7算法不公开,调用该算法时,需要通过加密芯片的接口进行调用。

php版本正常可以使用开源lpilp/guomi包来做签名、验签、加密等操作,但是开源的存在风险,建议是直接拉去下来自己打包,这里就不在讲解可以看开源库的文档

gitcode:https://gitcode.net/mirrors/lpilp/phpsm2sm3sm4

github:https://github.com/lpilp/phpsm2sm3sm4

如果是直接使用openssl的话可以参考:php的openssl加密扩展实现

如果是自行开发需要编译封装一个gmssl库或者其他库成为php的扩展,php -m 加载gmp、gmssl或者是gmkit

GmSSL:https://github.com/GmSSL/GmSSL-PHP

sop/asn1:https://github.com/sop/asn1


        微信图片_20230905162605.png

签名、验签:

<?php

namespace SmSign{

        use Sop\ASN1\Type\Constructed\Sequence;

        use Sop\ASN1\Type\Primitive\Integer;

        use Sop\ASN1\Type\UnspecifiedType;


        //  use Rtgm\sm\RtSm4;

        //  use Rtgm\sm\RtSm2;


        class SmSign

        {

                /**

                * 生成签名

                * @param $document

                * @param $prikey

                * @return string

                */

                public function doSign($document, $prikey){

                        //按64位截取

                        $privateKey = str_split($prikey, 64);

                        $key = [

                                'd' => hex2bin($privateKey[2]),

                                'P' => [

                                        hex2bin($privateKey[0]),

                                        hex2bin($privateKey[1])

                                ]

                        ];


                        [

                                'R'=> $r,

                                'S'=> $s

                        ] = gmkit_sm2_sign($key, $document);


                        $sequence = new Sequence(

                                new Integer(gmp_init(bin2hex($r), 16)),

                                new Integer(gmp_init(bin2hex($s), 16))

                        );

                        return bin2hex($sequence->toDER());


                                //sm2
                                //$sm2 = new RtSm2('hex', false);
                                //return $sm2->doSign($document, $prikey);

                }


                /**

                * 验证签名

                * @param $document

                * @param $sign

                * @param $pubkey

                * @return mixed

                */

                public function verifySign($document, $sign, $pubkey){

                        //公钥:去除开头04

                        $P = [

                                hex2bin(substr($pubkey, 2, 64)),

                                hex2bin(substr($pubkey,-64))

                        ];


                        //解码asn1编码得到原始的r、s再验签

                        $der = hex2bin($sign);

                        $seq = UnspecifiedType::fromDER($der)->asSequence();

                        $si = new Sequence(

                                new Integer(gmp_init($seq->at(0)->asInteger()->number(), 10)), // 十进制

                                new Integer(gmp_init($seq->at(1)->asInteger()->number(), 10))

                        );

                        $signature = [

                                "R" => hex2bin(substr(bin2hex($si->at(0)->toDER()), -64)), // 取出后64位

                                "S" => hex2bin(substr(bin2hex($si->at(1)->toDER()), -64))

                        ];

                        return gmkit_sm2_verify($P, $signature, $document);

                    

                        //sm2

                        //$sm2 = new RtSm2('hex', false);

                        //return  $sm2->verifySign($document, $sign, $pubkey);

                }

         }

    }


sm2加密、sm4加密:

<?php

namespace Sm {

        //  use Rtgm\sm\RtSm4;

        //  use Rtgm\sm\RtSm2;

class Sm

{

        /**

        * 补位

        * @param $lack

        * @return string

        */

        private function pad($lack) {

                return str_repeat(chr($lack), $lack);

        }


        /**

        * sm4加密

        * @param $content

        * @return string

        */

        public function sm4_encrypt($content = "", $aesKey = ""){

                if(empty($content) || empty($aesKey)){

                        return "";

                }


                //加密信息

                $content = $content.$this->pad(16 - (strlen($content) % 16));

                $c = '';

                foreach (str_split($content, 16) as $chunk) {

                        $c .= gmkit_sm4($aesKey, $chunk);

                }

                return base64_encode($c);


                //sm4

                //$sm4 = new RtSm4($aesKey);

                //return $sm4->encrypt($content, "sm4-ecb", "", "base64");

        }


        /**

        * 密码sm2加密

        * @param $publicKey

        * @return string

        */

        public function sm2_encrypt($document = "", $publicKey = ""){

                if(empty($document) || empty($publicKey)){

                        return "";

                }


                //公钥

                $P = [

                        hex2bin(substr($publicKey,2,64)),

                        hex2bin(substr($publicKey,-64))

                ];


                [

                        'C1'=> [$x, $y],

                        'C2'=> $C2,

                        'C3'=> $C3

                ] = gmkit_sm2_encrypt($P, $document);

                return "04".bin2hex($x).bin2hex($y).bin2hex($C2).bin2hex($C3);

        

                //密码加密

                //$sm2 = new RtSm2('hex', false);

                //$passwd = $sm2->doEncrypt($document, $publicKey, C1C2C3);

                //return "04" . $passwd; // doEncrypt做了substr($foreignPubKey, -128); 需要补一个04

        }

    }

}



只袄早~~~
感谢你的支持,我会继续努力!
扫码打赏,感谢您的支持!
php sm2 加密 签名 验签 sm4 

文明上网理性发言!

  • 还没有评论,沙发等你来抢