RSA非对称密钥接口开发文档

1、RSA加签:

1.1、规则:XML报文head的各个域(sign除外)与报文data各个域均看作String类型,按Key值字典序排序后得到待加签的内容,用自己商户的私钥对待加签的内 容进行MD5withRSA签名,再做Base64编码后作为sign值
例如待签名的值为:“1LTTV027430187654321测试商户pay00011.0”(amount的值+ appId的值+ mchntCd的值+ mchntNm的值+ msgId的值+ reqNo 的值+ version的值)
$header = [];
$postData = [];
$all = array_merge($header, $postData);
ksort($all);
$str = '';
foreach ($all as $key => $value) {
$str .= $value;
}
xyz = $this->userSign($str);
假如签名后为xyz

1.2、然后:将签名的结果放到<sign></sign>标签中得到 <sign>xyz</sign>

2、RSA报体加密

2.1、规则:用平台公钥对待加密报文体 使用RSA算法 进行分段加密(原始加签前的字符串转换成字节,再将字节按照117个字符加密一次,然后把所有的密文拼接成一个密文,将加密结果转换成base64的格式)。

//请求体数据加密
$postData = [];
ksort($postData);
$xml = "";
foreach ($postData as $key => $val) {
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
}
sec123 = $this->userEncryption($platform_id,$xml);

2.2、比如加密后得到结果为 sec123
将加密后的内容放到<data></data>标签中<data>sec123</data>

3、组合成发送报文

经过上面两步加密后,最终得到的发送报文为:
<xml>
<head>
<appId>LTTV</appId>
<version>1.0</version>
<msgId>pay</msgId>
<reqNo>0001</ reqNo>
<sign>xyz</sign>
</head>
<data>sec123</data>
</xml>


4、RSA报体验签


4.1、规则:响应报文转成数组互获取加密报文体,对报文体解密,解密后的报文体与报文头组装成非加密报文,按加签规则得到验签字符串
$result = $model->xmlToArray($res); //响应报文由xml字符串转出数组
$data = $result['data'];
$result['data'] = $model->userDecrypt($data); //对报文体加密数据进行解密操作
$data = '<xml>'.$result['data'].'</xml>'; //解密后的xml字符串需要添加根元素
$data = $model->xmlToArray($data); //报文体数据进行验签操作
$result['data'] = $data;
$signresult = $model->userVerify($result); //用户用平台公钥验签

5、RSA报体解密


5.1、规则:解密的时候需要讲密文解码,再128个字符解密一下,然后拼接成数据
$data = sec123
$result['data'] = $model->userDecrypt($data); //对报文体加密数据进行解密操作
$data = '<xml>'.$result['data'].'</xml>'; //解密后的xml字符串需要添加根元素
$data = $model->xmlToArray($data); //报文体数据进行验签操作

5.2、$result['data']为解密结果

备注:

/**
* 用户解密数据
* @param $data
* @return string
*/
public function userDecrypt($data){
$result = '';
$data = str_split(base64_decode($data), 128);
$pem = getCoKey('co_private'); //用户私钥解密
$key = openssl_pkey_get_private($pem);
foreach($data as $chunk)
{
openssl_private_decrypt($chunk,$decrypted,$key,OPENSSL_PKCS1_PADDING);
$result .= $decrypted;
}
return $result;
}

/**
* 用户私钥加签
* @param $data
* @param int $signMethod
* @return bool|string
*/
public function userSign($data,$signMethod=OPENSSL_ALGO_MD5){
$pem = getCoKey('co_private'); //用户私钥加签
$res = openssl_pkey_get_private($pem);
if (openssl_sign($data, $out, $res, $signMethod)) {
openssl_free_key($res); //释放资源
return (base64_encode($out));
}
return false;
}

/**
* 用户验签函数
* @param $res
* @return bool|int
*/
public function userVerify($res){
try {
//验签数据准备 降维 排序 拼接 验签
$tmp = array();
foreach($res as $ke => $val){
if(!empty($val)||$val == 0){
foreach($val as $k=>$v){
if(!empty($v||$v == 0)){
$tmp[$k]=$v;
}
}
}
}
unset($tmp['sign']);
ksort($tmp);
$str = '';
foreach ($tmp as $key => $value){
$str .= $value;
}
$platform_id = getPlatformId($res['head']['mchid']);
$result = $this->userVerifySign($platform_id,$res['head']['sign'],$str,OPENSSL_ALGO_MD5);
trace($result,'验签结果');
return $result;
} catch (Exception $e) {
trace($e->getMessage());
return false;
}
}

/**
* 用户验签
* @param $co_platform_id
* @param $sign
* @param $data
* @param int $signMethod
* @return int
*/
public function userVerifySign($co_platform_id,$sign, $data,$signMethod = OPENSSL_ALGO_SHA1)
{
$pem = getPlatformPublicKey($co_platform_id); //用户用平台公钥验签
trace($pem,'平台公钥');
$verifyKey = openssl_pkey_get_public($pem);
$sign = base64_decode($sign);
$r = openssl_verify($data, $sign, $verifyKey, $signMethod);
openssl_free_key($verifyKey);
return $r;
}

/**
* 平台公钥加密
* @param $co_platform_id
* @param $data
* @return string
*/
public function userEncryption($co_platform_id,$data){
$inputs = str_split($data,117);
$result = '';
$pem = getPlatformPublicKey($co_platform_id); //平台公钥加密
foreach ($inputs as $input){
openssl_public_encrypt($input,$output,$pem,OPENSSL_PKCS1_PADDING);
$result .= $output;
}
return base64_encode($result);
}

评论0条