联通国密对接 
                                                    
                        
                    
                    
  
                    
                    联通使用的证书是国密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
              
                    
                    
                    
 
推荐文章: