签名与验证过程:发起支付时商户服务端以自己的私钥进行签名后发送给平台,平台用商户公钥验证签名;回调时平台用自己的私钥对数据签名,商户用平台的公钥验证;整个过程使用两对秘钥。
终端窗口执行以下步骤生成交易所需 RSA2 秘钥(Windows 环境需提前下载安装 openssl 库)
1.openssl genrsa -out rsa_private_key.pem 2048
2.openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key_2048.pub
3.openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt > rsa_private_key_pkcs8.pem
注:也可自行搜索使用 第三方在线生成网站 或其他 本地SRA工具 生成
第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串。
第二步,用私钥将拼接成字符串进行加密
第三步,将得到的签名进行base64编码得到最终加密后的字符串
//test
public function generateSign($params=[],$private_key) {
$str = $this->getSignContent($params);
return $this->sign($str,$private_key);
}
public function getSignContent($params) {
if (isset($params['sign'])){
unset($params['sign']);
}
ksort($params);
$stringToBeSigned = "";
$i = 0;
foreach ($params as $k => $v) {
if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) {
// 转换成目标字符集
$v = $this->characet($v, 'utf8');
if ($i == 0) {
$stringToBeSigned .= "$k" . "=" . "$v";
} else {
$stringToBeSigned .= "&" . "$k" . "=" . "$v";
}
$i++;
}
}
unset ($k, $v);
return $stringToBeSigned;
}
function characet($data, $targetCharset) {
if (!empty($data)) {
$fileType ='utf8';
if (strcasecmp($fileType, $targetCharset) != 0) {
$data = mb_convert_encoding($data, $targetCharset, $fileType);
}
}
return $data;
}
public function checkEmpty($value) {
if (!isset($value))
return true;
if ($value === null)
return true;
if (trim($value) === "")
return true;
return false;
}
public function sign($data,$private_key) {
$priKey = $private_key;
try {
$res = "-----BEGIN RSA PRIVATE KEY-----\n" .
wordwrap($priKey, 64, "\n", true) .
"\n-----END RSA PRIVATE KEY-----";
openssl_sign($data, $sign, $res, version_compare(PHP_VERSION,'5.4.0', '<') ? SHA256 : OPENSSL_ALGO_SHA256); //OPENSSL_ALGO_SHA256是php5.4.8以上版本才支持
} catch (\Exception $e) {
return false;
}
$sign = base64_encode($sign);
return $sign;
}
public function verify_sign($params,$public_key='')
{
$ori_sign = $params['sign'];
$data = $this->getSignContent($params);
$public_content="-----BEGIN PUBLIC KEY-----\n" .
wordwrap($public_key, 64, "\n", true) .
"\n-----END PUBLIC KEY-----";
$public_key=openssl_get_publickey($public_content);
if($public_key){
$result = (bool)openssl_verify($data, base64_decode($ori_sign), $public_key, OPENSSL_ALGO_SHA256);
openssl_free_key($public_key);
return $result;
}else{
return false;
}
}
$sign = $this->generateSign($params=['test'=>1],$private_key='xxxxxx'); //签名
$verify_sign = $this->verify_sign($params=['test'=>1],$public_key='xxxxxx'); //验签 bool(true) 为验证通过