国密招商银行对接
前言#
国密主要有 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 协议》,转载必须注明作者和本文链接
推荐文章: