在Linux系统下运行以下命令生成:
如果提示输出密码,可以为空,直接回车
生成的公钥rsa_public_key.pem和密钥rsa_private_key.pem文件在根目录下
# openssl
# genrsa -out rsa_private_key.pem 2048 Generating RSA private key, 2048 bit long modulus
# pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt
# rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
$string:需要加密的字符串
$binary_signature:加密后保存到该变量中
$this->privateKey:RSA的私钥。(使用file_get_contents()读取私钥文件获取);
openssl_sign($string, $binary_signature, $this->privateKey, OPENSSL_ALGO_SHA256);
签名算法使用sha256withrsa算法,我方和渠道伙伴需交换RSA数字证书公钥用于验证签名,签名时,使用RSA数字证书私钥对签名参数串进行签名,RSA密用2048位及以上的,将签名值使用BASE64转码后填充到报文的数字签名域(Signature)。验证签名时,使用对方颁发的RSA数字证书公钥进行验签
/**
* 签名 + post请求
* @param array $param 请求参数
* @param string $method 第三方方法名
* @param string $api_method 接口名
* @param string $is_big 通道别名
* @param int $phone 手机号码
* @return mixed
*/
public function sign_post($param, $method, $api_method, $is_big, $phone)
{
$param['reqTime'] = date('YmdHis');
$param['partnerId'] = $this->partnerId;
$this->log($param, $api_method, $is_big, '签名前数据:', $phone);
$signature = $this->makeSign($param);
$this->log($signature, $api_method, $is_big, '签名值:');
$param['signature'] = $signature;
$types = explode('_',$api_method);
if($types[0] == 'sk'){
$requestUrl = $this->edUrl . $method;
}else{
$requestUrl = $this->zdUrl . $method;
}
$this->log($requestUrl, $api_method, $is_big, '请求url:');
$this->log($param, $api_method, $is_big, '请求报文:');
$res = $this->curl($requestUrl, $param);
$this->log($res, $api_method, $is_big, '响应报文:');
return $res;
}
/**
* 生成签名
* @param $params array 请求参数
* @param $privateKey string 秘钥
* @return $sign string 签名内容
*/
public function makeSign($params)
{
//签名步骤一:按字典序排序参数,再把所有数组值以“&”字符连接起来
ksort($params);
$string = $this->toUrlParams($params);
openssl_sign($string, $binary_signature, $this->privateKey, OPENSSL_ALGO_SHA256);
$sign = base64_encode($binary_signature);
return $sign;
}
/**
* 格式化参数格式化成url参数
* @param $params array
*/
public function toUrlParams($params)
{
$buff = "";
foreach ($params as $k => $v) {
if ($v != "" && !is_array($v)) {
$buff .= $k . "=" . $v . "&";
}
}
$buff = trim($buff, "&");
return $buff;
}
//接口post请求
public function curl($url = '', $data = '')
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
if (!empty($data)) {
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 30); //超时时间30秒
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
curl_close($ch);
return $output;
}
/**
* 验签
* @param $data array 需要验签的数据
*/
public function verifySign($data, $publicKey)
{
if (empty($data) || empty($data['signature'])) {
return false;
}
$sign = $data['signature'];
unset($data['signature']);
ksort($data);
$string = $this->ToUrlParams($data);
$pubKey = "-----BEGIN PUBLIC KEY-----\n" .
wordwrap($publicKey, 64, "\n", true) .
"\n-----END PUBLIC KEY-----";
$result = (bool)openssl_verify($string, base64_decode($sign), $pubKey, OPENSSL_ALGO_SHA256);
return $result;
}
/**
* 日志记录
* @param $data /内容
* @param $method /方法名
* @param $phone /手机号
* @param string $is_big /通道别名
* @param string $title /标题
*/
public function Log($data, $method, $is_big, $title, $phone = '')
{
$str = is_array($data) ? json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) : $data;
if (empty($phone)) {
$content = '【' . date('Y-m-d H:i:s') . '】' . $title . $str . PHP_EOL;
} else {
$content = ' phone:' . $phone . '【' . date('Y-m-d H:i:s') . '】' . $title . $str . PHP_EOL;
}
$path = APPPATH . "../PAYLOG/$is_big/$method/";
if (!is_dir($path)) { //判断目录是否存在 不存在就创建
mkdir($path, 0777, true);
}
file_put_contents($path . date("Y-m-d") . '.txt', $content, FILE_APPEND);
//换行分割
file_put_contents($path . date("Y-m-d") . '.txt', '------------------------' . PHP_EOL, FILE_APPEND);
}