国密招商银行对接
前言
国密主要有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示例
// 工具函数 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; } ############################数据加密开始################################ // 公钥 $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 = formatHex($point[0]->getContent()); $pointY = 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"); var_dump($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'); $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); ############################返回数据验证结束################################
本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由系统于 3年前 自动加精
关于 LearnKu
mark
mark
不错,最近刚好有接触这块的业务
亲您好,我运行了你的demo,发现最后一步校验签名的结果为flase,请问这需要改动吗?
ubuntu安装的php和openssl默认支持 国密算法。
最近刚对接了江苏银行e融支付,也只有java版本。
接口和文档字段有出入,java demo跑不通,测试支付环境整的也跑不通
唉,直接在生产环境,对接了。其中费了点事就是证书加密后和银行那对不上。
@失色天空 调用招行接口有的验签返回true 有的返回false,添加账户子单元返回验签不成功
mark
mark
mark
基于openssl开发的sm2国密扩展,已经和博主的代码比对过互通的,除了加密的结果多了个04开头的标记
gitee.com/state-secret-series/open...
mark
之前与该库的作者交流过,后面发现了招商银行java版本的一些签名方式的问题,因此后面作者特地针对招商银行的问题做了特殊的工作,具体的大家可以进该库的github地址看一下
mark
我调用这个demo签名加密可以,但是验签名一直返回false。@
楼主,你好,想问下,key是怎么获取的啊?
@linpf 你好, lajitengxun10086 这个是你的微信么,方便加你下么,有关于国密的技术问题
加密的参数需要排序
pfx证书怎么转私钥
有没有大佬处理过SM4密钥和向量是32位的?
解决不了的可以联系我 vx:onedayis86400s
曾经碰了一鼻子灰,后来用银行提供的 SDK 部署了个专门处理加解密、签名、验签的服务,总算绕过去了
laravel9目前还不能使用这个包么?兄弟有没得7.0版本的 SM3和SM4加密 公司服务器php版本是7.0的