数字签名
具体要求如下:
(1) 第一步,设所有发送或者接收到的数据为集合 M,将集合 M 内非空参数值的参数按照参数名 ASCII 码从小到大排序(字典序),使用 URL 键值对的 格式(即 key1=value1&key2=value2…)拼接成字符串 stringA。
特别注意以下重要规则:
参数名 ASCII 码从小到大排序(字典序);
如果参数的值为空不参与签名;
参数名区分大小写;
(2)第二步,在 stringA 最后拼接上 key 得到 stringSignTemp 字符串,并对 stringSignTemp 进行 HMAC 运算,再将得到的字符串所有字符转换为大写,得到 tempsign 值 tempsignValue,并对 tempsignValue 进行 RSA 签名得到 sign 的值 signValue。
举例:
假设传送的参数如下:
service:pay.jds.authpay
mch_id:930ea5d5a258
version:1.0
jds_org_id:jds930ea5d5a258f4f
nonce_str:ibuaiVcKdpRxkhJA
1.对参数按照 key=value 的格式,并按照参数名 ASCII 字典序排序生成字符串:
jds_org_id=jds930ea5d5a258f4f&mch_id=930ea5d5a258&nonce_str=ibuaiVcKdpRxkhJA&service=pay.jds.authpay&version=1.0
2.连接商户 key:
jds_org_id=jds930ea5d5a258f4f&mch_id=930ea5d5a258&nonce_str=ibuaiVcKdpRxkhJA&service=pay.jds.authpay&version=1.0&key=192006250b4c09247ec02edce69f6a2d
3.生成 tempsign 并转成大写:
tempsign=11E23FE749528FEDC879024C374857DF
4.生成 sign 并对 tempsign 进行 RSA 加密签名:
rsasign=RSA2(tempsign)
5.对 rsasign 进行 base64 转码:
base64sign=base64(rsasign)
6.对 base64sign 进行 urlEncoded 转码得到提交的 sign 值:
sign=urlEncoded(base64sign)
下面是我的代码:
//1.对参数按照 key=value 的格式,并按照参数名 ASCII 字典序排序生成字符串
$data = array_filter($data);
ksort($data);
$stringA = '';
foreach ($data as $key => $val) {
$stringA .= "&{$key}={$val}";
}
$stringA = ltrim($stringA, '&');
//2.连接商户 key
$key = config('jdspay.key');
$stringSignTemp = $stringA . '&key=' . $key;
//3.生成 tempsign 并转成大写:
$tempsign = hash_hmac('sha256', $stringSignTemp, $key);
$tempsign = strtoupper($tempsign);
//4.生成 sign 并对 tempsign 进行 RSA 加密签名
$priKey = config('jdspay.private_key');
$priKey = chunk_split($priKey, 64, "\n");
$priKey = "-----BEGIN RSA PRIVATE KEY-----\n$priKey-----END RSA PRIVATE KEY-----\n";
openssl_sign($tempsign, $sign, $priKey, OPENSSL_ALGO_SHA256);
//5.对 rsasign 进行 base64 转码
$sign = base64_encode($sign);
//对 base64sign 进行 urlEncoded 转码得到提交的 sign 值
$sign = urlencode($sign);
不知道哪里不对,但是始终验签错误,有没有大佬帮忙指点一下
给你个建议,通过base64传输过程中,要通过安全的base64进行加解密,对+/=这几个进行替换。
字符集 utf8 gbk 一致吗