签名与验证过程:发起支付时商户服务端以自己的私钥进行签名后发送给平台,平台用商户公钥验证签名;回调时平台用自己的私钥对数据签名,商户用平台的公钥验证;整个过程使用两对秘钥。
终端窗口执行以下步骤生成交易所需 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) 为验证通过