cmbYouku_Api/app/service/util/CmbLifeUtils.php

253 lines
7.5 KiB
PHP
Raw Permalink Normal View History

2024-07-01 15:57:07 +08:00
<?php
namespace app\service\util;
use app\exception\LogicException;
use app\util\sm\cmb\Sm;
use app\util\StringUtil;
class CmbLifeUtils
{
protected static string $cmbLifeProtocolPrefix = 'cmblife://';
/**
* 生成掌上生活协议,带有签名
* @param string $funcName
* @param array $params
* @return string
* @throws LogicException
*/
public static function genProtocol(string $funcName, array $params): string
{
if (empty($funcName)) {
throw new LogicException('funcName不能为空');
}
// 处理公共参数
$cmbConfig = config('cmb');
$params['mid'] = $cmbConfig['mid'];
$params['aid'] = $cmbConfig['aid'];
$params['date'] = date('YmdHis');
$params['random'] = StringUtil::generateRandomString(32);// 随机数
$params['keyAlias'] = 'CO_PUB_KEY_SM2';
$params['cmbKeyAlias'] = 'SM2_CMBLIFE';
$signBody = self::assembleProtocol($funcName, $params, false); // 不需要urlEncode
$signKey = $cmbConfig['merchant_sm2_pri_key'];
$sign = Sm::sign($signKey, $signBody); //sm2
$params['sign'] = $sign;
return self::assembleProtocol($funcName, $params, true);
}
/***
* 拼接掌上生活协议
* @param String $funcName
* @param array $params
* @param bool $isUrlEncode
* @return string
*/
public static function assembleProtocol(string $funcName, array $params, bool $isUrlEncode)
{
$prefix = self::$cmbLifeProtocolPrefix . $funcName;
return self::getAssembleUrl($prefix, $params, $isUrlEncode);
}
/**
* 拼接签名字符串
* @param String $prefix
* @param String $queryString
* @return String
*/
public static function assembleUrl(string $prefix, string $queryString): string
{
if (empty($prefix)) {
return $queryString;
} else {
$char = strpos($prefix, '?') !== false ? '&' : '?';
return $prefix . $char . $queryString;
}
}
/**
* 拼接签名字符串
* @param string $prefix
* @param array $params
* @param bool $isUrlEncode
* @return String
*/
public static function getAssembleUrl(string $prefix, array $params, bool $isUrlEncode): string
{
return self::assembleUrl($prefix, self::mapToQueryString($params, true, $isUrlEncode));
}
/**
* 参数转为queryString
* @param array $params
* @param bool $isSort 是否排序
* @param bool $isUrlEncode 是否需要urlEncode
* @return string
*/
public static function mapToQueryString(array $params, bool $isSort, bool $isUrlEncode = true): string
{
if ($isSort) {
ksort($params);
}
$queryString = '';
foreach ($params as $key => $value) {
if (empty($value)) {
continue;
}
if ($isUrlEncode) {
$value = urlencode($value);
}
$queryString .= $key . '=' . $value . '&';
}
return trim($queryString, '&');
}
/**
* 加密
* @param string $encryptBody
* @param string $encryptKey 加密使用的key SM2公钥
* @return string
* @throws LogicException
*/
public static function encrypt(string $encryptBody, string $encryptKey)
{
if (empty($encryptBody)) {
throw new LogicException('报文不能为空');
}
if (empty($encryptKey)) {
throw new LogicException('公钥不能为空');
}
return Sm::sm4Encrypt($encryptKey, $encryptBody);
}
/**
* 解密
* @param string $encryptBody
* @param string $decryptKey 解密使用的Key SM2私钥
* @throws LogicException
*/
public static function decrypt(string $encryptBody, string $decryptKey)
{
if (empty($encryptBody)) {
throw new LogicException('报文不能为空!');
}
if (empty($decryptKey)) {
throw new LogicException('秘钥不能为空!');
}
return json_decode(Sm::sm4decrypt($decryptKey, $encryptBody), true);
}
/**
* 签名
* @param string $signBody
* @param string $signKey
* @param string $algorithmEnum
* @return string
* @throws LogicException
*/
public static function sign(string $signBody, string $signKey)
{
if (empty($signBody)) {
throw new LogicException('待签名数据不能为空!');
}
if (empty($signKey)) {
throw new LogicException('私钥不能为空');
}
return Sm::sign($signKey, $signBody);
}
/**
* 验签国密算法SM3WithSM2
* @param string $verifyBody
* @param string $sign
* @param string $verifyKey sm2公钥
* @return bool
* @throws LogicException
*/
public static function verify(string $verifyBody, string $sign, string $verifyKey)
{
if (empty($verifyBody)) {
throw new LogicException('验签数据不能为空');
}
if (empty($sign)) {
throw new LogicException("签名不能为空");
}
if (empty($verifyKey)) {
throw new LogicException("公钥不能为空");
}
return Sm::verify($verifyKey, $sign, $verifyBody);
}
/**
* 对请求签名
* @param string $funcName
* @param array $params
* @param string $signKey sm2 私钥
* @param string $signAlgorithm SM3WithSM2
* @return string
*/
public static function signForRequest(string $funcName, array $params, string $signKey, string $signAlgorithm = 'SM3WithSM2')
{
if (!empty($funcName) && !strpos($funcName, '.json')) {
$funcName = $funcName . '.json';
}
$assembleUrl = self::getAssembleUrl($funcName, $params, false);
return self::sign($assembleUrl, $signKey);
}
/**
* 对响应签名
* @param array $params
* @return string
* @throws LogicException
*/
public static function signForResponse(array $params)
{
if (empty($params)) {
throw new LogicException('参数不能为空');
}
$cmbConfig = config('cmb');
$signKey = $cmbConfig['merchant_sm2_pri_key'];
$assembleUrl = self::getAssembleUrl('', $params, false);
unset($params['sign']);
return self::sign($assembleUrl, $signKey);
}
/**
* 对响应验签
* @param array $data
* @return bool true 验签成功 false 验签失败
* @throws LogicException
*/
public static function verifyForResponse(array $data): bool
{
if (empty($data)) {
throw new LogicException('参数不能为空');
}
$cmbConfig = config('cmb');
$verifyKey = $cmbConfig['merchant_sm2_pub_key'];
$sign = $data['sign'];
unset($data['sign']);
return self::verify(self::getAssembleUrl('', $data, false), $sign, $verifyKey);
}
/**
* @param array $params
* @param string $verifyKey 验签所使用的Key为掌上生活公钥
* @return bool
* @throws LogicException
*/
public static function verifyForRequest(array $params, string $verifyKey): bool
{
if (empty($params)) {
throw new LogicException('参数不能为空');
}
$sign = $params['sign'];
unset($params['sign']);
$assembleUrl = self::getAssembleUrl('', $params, false);
return self::verify($assembleUrl, $sign, $verifyKey);
}
}