SM国密招商银行对接

前言

国密主要有 SM1,SM2,SM3,SM4。密钥长度和分组长度均为 128 位。

    SM1
    为对称加密。其加密强度与 AES (高级加密标准,Advanced Encryption Standard) 相当。该算法不公开,调用该算法时,需要通过加密芯片的接口进行调用。

    SM2
    为非对称加密,基于 ECC。该算法已公开。由于该算法基于 ECC,故其签名速度与秘钥生成速度都快于 RSA。ECC 256 位(SM2 采用的就是 ECC 256 位的一种)安全强度比 RSA 2048 位高,但运算速度快于 RSA。

    SM3
    为消息摘要。可以用 MD5 作为对比理解。该算法已公开。校验结果为 256 位。

    SM4
    为对称加密,无线局域网标准的分组数据算法,密钥长度和分组长度均为 128 位。

代码
  • 安装包
    composer require lpilp/guomi

  • 示例

protected function execute(Input $input, Output $output)

    {


############################数据加密开始################################

// 公钥

        $publicKey = 'BNsIe9U0x8IeSe4h/dxUzVEz9pie0hDSfMRINRXc7s1UIXfkExnYECF4QqJ2SnHxLv3z/99gsfDQrQ6dzN5lZj0=';

// 私钥

        $privateKey = 'NBtl7WnuUtA2v5FaebEkU0/Jj1IodLGT6lQqwkzmd2E=';

// base64私钥转二进制

        $privateKey = base64_decode($privateKey);

// 二进制转十六进制字符串

        $privateKey = unpack("H*", $privateKey)[1];

// 待加密的数据

        $data = '{"request":{"body":{"ntbusmody":[{"busmod":"00001"}],"ntdumaddx1":[{"bbknbr":"75","dyanam":"招商测试","dyanbr":"11111111111","eftdat":"20220602","inbacc":"755936020410404","ovrctl":"N","yurref":"596620626253316098"}]},"head":{"funcode":"NTDUMADD","reqid":"202206021511010000001","userid":"B000001631"}},"signature":{"sigdat":"__signature_sigdat__","sigtim":"20220602161503"}}';

// 生成签名开始

        $sm2 = new RtSm2("base64");

// 将用户id填充到16个字节

        $userId = sprintf('%-016s', "B000001631");

// 使用rsa的私钥生成签名(注意这里是私钥!私钥!私钥!)

        $sign = $sm2->doSign($data, $privateKey, $userId);

// 将base64的签名还原为二进制

        $sign = base64_decode($sign);

// 处理二进制数据

        $point = \FG\ASN1\ASNObject::fromBinary($sign)->getChildren();

        $pointX = $this->formatHex($point[0]->getContent());

        $pointY = $this->formatHex($point[1]->getContent());

        $sign = $pointX . $pointY;

        $sign = base64_encode(hex2bin($sign));

// 替换签名字段

        $data = str_replace('__signature_sigdat__', $sign, $data);

// 对数据进行对称加密(换成你自己的key)

        $sm4 = new RtSm4('VuAzSWQhsoNqzn0K');

// 这里使用的具名参数的写法,低版本的php改成顺序传入参数就行

        $encryptData = $sm4->encrypt($data, 'sm4-cbc', $iv = $userId, "base64");

        echo ($encryptData);

        die;

############################数据加密结束################################

############################返回数据验证开始################################

        $decryptData = "LkQOOa0kJr7xWxyhr1kj4mf31f1lZOv5bURemjcALkmQXGeKBIVnR6f+BIN8g6UvhHy08LKrmyYTq9LBXQBI95i7Ht/4OWTRFoFG/lCYT39cr50a426UgreuF4NUrUdCGoItHiwTmCcfJStqjdGXY0O0lr9YR2GJZEOtpllnRThoIWEIdPUvQMtUyzfQKuOZ6s7r6V3jirKUFuaeuFtuZ96RliOCqQa/BdCY/qHnjVaMEoZNTYeHeUIcZs43nCxaMcvaBFTZ9wbBjNf3jwmi/TZKHIcXLQpIxtWdYoOC12dgKkeBL83xaHCGYpvkOO0IFML8XbJR1oQJdvvF49WCN6HmrcikG0fPjX+AzTxT1odHsAwHk78m9galKfkslUDrT+bq4qplw3ByOQA+5WfzmNPsSgGYLfE6va+5EbXieaMW6pPs7yiWUyOhpVOpBV+6q4cwXWeGgDgUhXQ1dTKFqqJQBMKX8iRvXgYFTmwSzZHvH7VZmtuf7gZMMtycSUFb";

// 返回结果解密,这里使用的具名参数的写法,低版本的php改成顺序传入参数就行

        $json = $sm4->decrypt($decryptData, $type = 'sm4-cbc', $iv = $userId, $formatInput = 'base64');

        // $res = openssl_decrypt(base64_decode($decryptData),'sm4-cbc','VuAzSWQhsoNqzn0K',OPENSSL_RAW_DATA,$userId);

        $data = json_decode($json, true);

        var_dump($data);

        die;

// 验证签名是否正确

        $sign = $data["signature"]["sigdat"];

// 将数据中的签名重置

        $data["signature"]["sigdat"] = "__signature_sigdat__";

        $json = json_encode($data, 256);

        $signHex = bin2hex(base64_decode($sign));

        $r = substr($signHex, 0, 64);

        $s = substr($signHex, 64, 64);

        $r = gmp_init($r, 16);

        $s = gmp_init($s, 16);

        $signature = new \Mdanter\Ecc\Crypto\Signature\Signature($r, $s);

        $serializer = new DerSignatureSerializer();

        $serializedSig = $serializer->serialize($signature);

        $sign = base64_encode($serializedSig);

        $publicKey = unpack("H*", base64_decode($publicKey))[1];

        $b = $sm2->verifySign($json, $sign, $publicKey, $userId);

        var_dump($b);

############################返回数据验证结束################################

    }




    // 工具函数

    public function formatHex($dec)

    {

        $hex = gmp_strval(gmp_init($dec, 10), 16);

        $len = strlen($hex);

        if ($len == 64) {

            return $hex;

        }

        if ($len < 64) {

            $hex = str_pad($hex, 64, "0", STR_PAD_LEFT);

        } else {

            $hex = substr($hex, $len - 64, 64);

        }

        return $hex;

    }

但openssl 1.1.1 已支持以下加密算法可以尝试一下

/**

 * openssl 1.1.1 已支持以下加密算法

 * aes-128-cbc,aes-128-cbc-hmac-sha1,aes-128-cbc-hmac-sha256,aes-128-ccm,aes-128-cfb,aes-128-cfb1,aes-128-cfb8,aes-128-ctr,aes-128-ecb,aes-128-gcm,aes-128-ocb,aes-128-ofb,aes-128-xts,aes-192-cbc,aes-192-ccm,aes-192-cfb,aes-192-cfb1,aes-192-cfb8,aes-192-ctr,aes-192-ecb,aes-192-gcm,aes-192-ocb,aes-192-ofb,aes-256-cbc,aes-256-cbc-hmac-sha1,aes-256-cbc-hmac-sha256,aes-256-ccm,aes-256-cfb,aes-256-cfb1,aes-256-cfb8,aes-256-ctr,aes-256-ecb,aes-256-gcm,aes-256-ocb,aes-256-ofb,aes-256-xts,aes128,aes128-wrap,aes192,aes192-wrap,aes256,aes256-wrap,aria-128-cbc,aria-128-ccm,aria-128-cfb,aria-128-cfb1,aria-128-cfb8,aria-128-ctr,aria-128-ecb,aria-128-gcm,aria-128-ofb,aria-192-cbc,aria-192-ccm,aria-192-cfb,aria-192-cfb1,aria-192-cfb8,aria-192-ctr,aria-192-ecb,aria-192-gcm,aria-192-ofb,aria-256-cbc,aria-256-ccm,aria-256-cfb,aria-256-cfb1,aria-256-cfb8,aria-256-ctr,aria-256-ecb,aria-256-gcm,aria-256-ofb,aria128,aria192,aria256,bf,bf-cbc,bf-cfb,bf-ecb,bf-ofb,blowfish,camellia-128-cbc,camellia-128-cfb,camellia-128-cfb1,camellia-128-cfb8,camellia-128-ctr,camellia-128-ecb,camellia-128-ofb,camellia-192-cbc,camellia-192-cfb,camellia-192-cfb1,camellia-192-cfb8,camellia-192-ctr,camellia-192-ecb,camellia-192-ofb,camellia-256-cbc,camellia-256-cfb,camellia-256-cfb1,camellia-256-cfb8,camellia-256-ctr,camellia-256-ecb,camellia-256-ofb,camellia128,camellia192,camellia256,cast,cast-cbc,cast5-cbc,cast5-cfb,cast5-ecb,cast5-ofb,chacha20,chacha20-poly1305,des,des-cbc,des-cfb,des-cfb1,des-cfb8,des-ecb,des-ede,des-ede-cbc,des-ede-cfb,des-ede-ecb,des-ede-ofb,des-ede3,des-ede3-cbc,des-ede3-cfb,des-ede3-cfb1,des-ede3-cfb8,des-ede3-ecb,des-ede3-ofb,des-ofb,des3,des3-wrap,desx,desx-cbc,id-aes128-CCM,id-aes128-GCM,id-aes128-wrap,id-aes128-wrap-pad,id-aes192-CCM,id-aes192-GCM,id-aes192-wrap,id-aes192-wrap-pad,id-aes256-CCM,id-aes256-GCM,id-aes256-wrap,id-aes256-wrap-pad,id-smime-alg-CMS3DESwrap,idea,idea-cbc,idea-cfb,idea-ecb,idea-ofb,rc2,rc2-128,rc2-40,rc2-40-cbc,rc2-64,rc2-64-cbc,rc2-cbc,rc2-cfb,rc2-ecb,rc2-ofb,rc4,rc4-40,rc4-hmac-md5,seed,seed-cbc,seed-cfb,seed-ecb,seed-ofb,

 * sm4,sm4-cbc,sm4-cfb,sm4-ctr,sm4-ecb,sm4-ofb

 * 其中支持sm4相关的各种算法模式,缺省使用的是cbc算法

 * 加密串短可以使用ecb,计算速度快,串长的话ecb的扩散性差,安全性不足,就使用带向量的其他算法如cbc

 */

// echo implode(',',openssl_get_cipher_methods(true));


// $ivlen = openssl_cipher_iv_length("sm4");

// $iv = openssl_random_pseudo_bytes($ivlen);

// sm4的iv长度是16字符

$key = "0123456789abcdef";

$iv = "1234567887654321"; 


$data = 'hello world!';


//  openssl_encrypt($plaintext, "sms4", $key, $options=0, $iv);

// options = 0 base64, 1( OPENSSL_RAW_DATA ):原始二进制 , 这里为了与tsm4对比,就使用hex方式

// sm4-ecb算法

$ciphertext =openssl_encrypt($data, "sm4-ecb", $key, $options=OPENSSL_RAW_DATA);

$enc = bin2hex($ciphertext);

echo "encrypt: $enc\n";

$original_plaintext = openssl_decrypt($ciphertext, "sm4-ecb", $key, $options=OPENSSL_RAW_DATA);

echo "encrypt: $original_plaintext\n";


// 缺省的sm4算法,使用的是sm4-cbc模式

$ciphertext =openssl_encrypt($data, "sm4", $key, $options=OPENSSL_RAW_DATA,$iv);

// $ciphertext =openssl_encrypt($data, "sm4-cbc", $key, $options=OPENSSL_RAW_DATA,$iv);  //这两个是一样的

$enc = bin2hex($ciphertext);

echo "encrypt: $enc\n";

$original_plaintext = openssl_decrypt($ciphertext, "sm4", $key, $options=OPENSSL_RAW_DATA,$iv);

echo "encrypt: $original_plaintext\n";


// sm4-cfb,sm4-ctr,sm4-ofb 的使用方法一样

$ciphertext =openssl_encrypt($data, "sm4-cfb", $key, $options=OPENSSL_RAW_DATA,$iv);

$enc = bin2hex($ciphertext);

echo "encrypt: $enc\n";

$original_plaintext = openssl_decrypt($ciphertext, "sm4-cfb", $key, $options=OPENSSL_RAW_DATA,$iv);

echo "encrypt: $original_plaintext\n";

转载:国密招商银行对接 | Laravel China 社区

相关链接:

openssl-ext-sm2: 基于openssl密码库编写的sm2国密算法PHP扩展

  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值