RSA(SHA1WithRSA)签名逻辑
A.签名字符串为除了sign之外的其他非空字段组成键值对
B.所有参与签名的字段,按字段名的ASCII码从小到大排序后,使用URL的键值对的格式(即key1=value1&key2=value2)拼接成字符串
C.用商户的RSA私钥进行签名
D.请求接口成功后,把系统返回的JSON字符串数据除sign之外的其他所有非空字段组成键值对,进行同样的排序和组装处理,并用公钥进行验签
// 签名
public static function sign($params)
{
$signString = self::getSignData($params);
// 私钥加密
$privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" .
wordwrap(self::$privateKey, 64, "\n", true) .
"\n-----END RSA PRIVATE KEY-----";
$key = openssl_pkey_get_private($privateKey);
if ($key === false) {
throw new Exception('非法的PKCS8 Private Key格式');
}
$signature = '';
$success = openssl_sign($signString, $signature, $key, OPENSSL_ALGO_SHA1);
if (!$success) {
throw new Exception('生成签名失败');
}
return base64_encode($signature);
}
// 验签
public static function verifyData($data, $sign)
{
$signStr = self::getSignData($data);
$pubKey = "-----BEGIN PUBLIC KEY-----\n" .
wordwrap(self::$publicKey, 64, "\n", true) .
"\n-----END PUBLIC KEY-----";
if (!$pubKey) {
throw new Exception('RSA公钥错误。请检查公钥文件格式是否正确');
}
$res = (bool)openssl_verify($signStr, base64_decode($sign), $pubKey);
if (!$res) {
throw new Exception('签名验证失败');
}
return true;
}
// 组装数据
private static function getSignData($params)
{
unset($params['sign']);
// 按照ASCII码递增排序
ksort($params);
// 组合成 参数=参数值 的格式,并且用 & 字符连接
$signString = '';
$i = 0;
foreach ($params as $k => $value) {
if ($i == 0) {
$signString .= $k . '=' . $value;
} else {
$signString .= '&' . $k . '=' . $value;
}
$i++;
}
return $signString;
} 