签名算法

签名与验证过程:发起支付时商户服务端以自己的私钥进行签名后发送给平台,平台用商户公钥验证签名;回调时平台用自己的私钥对数据签名,商户用平台的公钥验证;整个过程使用两对秘钥。

终端窗口执行以下步骤生成交易所需 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) 为验证通过