联通国密对接
联通使用的证书是国密PKCS#12格式文件,但是使用openssl_pkcs12_read一直没读取出来,后面使用联通demo直接获取的明文来使用,老项目安装扩展和composer包这条路走不通
1.安装composer包,需要启用gmp扩展
composer require phpseclib/phpseclib
composer require lpilp/guomi
2.需要修改guomi源代码,返回值时补上 04
public function initEncipher($userPoint, $foreignKey = null)
{
if (empty($foreignKey)) {
$sm2 = new RtSm2();
$foreignKey = $sm2->generatekey();
}
$foreignPriKey = $foreignKey[0];
$foreignPubKey = $foreignKey[1];
$this->p2 = $userPoint->mul(gmp_init($foreignPriKey, 16));
$this->reset();
return '04' .substr($foreignPubKey, -128);
}
3.使用公钥验签
/**
* sm2验签
* @param $signStr
* @param $sign
* @return bool
*/
public function sm2VerifySign($signStr, $sign)
{
$publicKey = unpack("H*", base64_decode("使用java读取出来的公钥"))[1];
$sm2 = new RtSm2('base64');
return $sm2->verifySign($signStr,$sign,$publicKey);
}
4.解密,首先需要把待解密数据做格式转换
use phpseclib3\File\ASN1;
private function base64url_decode($data) {
return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_BOTH));//STR_PAD_RIGHT
}
private function sm2ASN1ToC1C3C2($data)
{
$der = ASN1::decodeBER(base64_decode($data));
$x = "";
$y = "";
if (isset($der[0]["content"][0]["content"])) {
$x = $der[0]["content"][0]["content"]->toHex();
}
if (isset($der[0]["content"][1]["content"])) {
$y = $der[0]["content"][1]["content"]->toHex();
}
$hash = bin2hex($der[0]["content"][2]["content"] ?? "");
$ct = bin2hex($der[0]["content"][3]["content"] ?? "");
$x = str_pad($x, 64, "0", STR_PAD_LEFT);
$y = str_pad($y, 64, "0", STR_PAD_LEFT);
return $x . $y . $hash . $ct;
}
public function decrypt($reqMsg,$appkey,$type='')
{
$appkey = $this->sm2ASN1ToC1C3C2($appkey);
$sm2 = new RtSm2();
$res = $sm2->doDecrypt($appkey, "解密密钥");
if($type){
$smk = bin2hex($res);
}else{
$smk = base64_encode($res);
}
$reqMsg = $this->base64url_decode($reqMsg);
$data = openssl_decrypt($reqMsg, 'SM4-ECB', hex2bin($smk),OPENSSL_RAW_DATA);
if(!$json){
return [];
}
return json_decode($data,true);
}
5.加密
function base64url_encode($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
$sm4Key = random_bytes(16);
//加密得到appkey
$sm2 = new RtSm2('base64');
$publicKey = unpack("H*", base64_decode("公钥"))[1];
$appRspKey = $sm2->doEncrypt($sm4Key, $publicKey);
$appKey = base64_encode(hex2bin($appRspKey));
//加密业务数据
$ciphertext = openssl_encrypt("业务数据", 'SM4-ECB', $sm4Key, OPENSSL_RAW_DATA);
$msg = base64url_encode($ciphertext);
6.生成签名
public function sm2Sign($signStr)
{
$sm2 = new RtSm2("base64");
$sign = $sm2->doSign($signStr, "签名私钥");
$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;
return base64_encode(hex2bin($sign));
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
关于 LearnKu
推荐文章: