• 首页
  • 支付
  • 代付
  • 账户相关
  • 附录
    • 创建订单
    • 查询订单
    • 回调通知
    • 代付反查
    • 签名规则

签名规则说明

  • sign算法说明:
  • 为空的参数不参数与签名
  • 参数按键值+数值的ASCII编码顺序拼接,生成signData。使用RSA私钥,通过SHA1withRSA算法,RSA加密统一私钥加密,公钥验签。
  • RSA公私钥可以通过https://www.bejson.com/enc/rsa/ 获取(密钥长度选择1024bit,生成的公钥是以MIG开头,AB结尾),或者自己生成密钥

signData示列

  • amount=100&bankCode=ICBC&bankcardAccountName=张三&bankcardAccountNo=123456789123456789&merchantId=80008&merchantOrderNo=20230630202003&notifyUrl=http://www.baidu.com&version=1.0.1

RSA私钥加密signData示列

  • kqzun1v2Iw1nAr9bYzKsRuwKupKXppwNFVW34sLqCD7GmuXAaw1jvcXqBhDD9camhdt/1Yq1D7AyDWDOg60DHAigrbULuek+ZlwiRRiFJOVZTbJRnkewmfDXCVbPOfIGf0NTFjxcJqabL/5SKngwDEGav65+NlJhtgHGfo5UvoI=

加密验签代码参考(JAVA)

  • # 请求参数
    Map<String, String> params = new TreeMap<>();
    params.put("merchantOrderNo", "20230630202003");
    params.put("amount", "100");
    params.put("bankCode", "ICBC");
    params.put("bankcardAccountNo", "123456789123456789");
    params.put("bankcardAccountName", "张三");
    params.put("notifyUrl", "https://www.baidu.com");
    params.put("merchantId", Const.MERCH_ID);
    params.put("version", Const.VERSION);

    String signData = data.entrySet().stream().filter(e -> StringUtils.isNotEmpty(e.getValue())).map(e -> e.getKey().concat("=").concat(e.getValue())).collect(Collectors.joining("&"));
    params.put("sign", RSAUtils.sign(signData, privateKey));

    HttpUtils.post(url, JSON.toJSONString(params));


    # RSAUtils工具类
    import com.alibaba.fastjson.JSONObject;
    import com.demo.Const.Const;
    import org.apache.commons.lang3.StringUtils;

    import java.nio.charset.StandardCharsets;
    import java.security.*;
    import java.security.spec.InvalidKeySpecException;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    import java.util.Base64;
    import java.util.Map;
    import java.util.TreeMap;
    import java.util.stream.Collectors;

    /**
    * 工具类
    */
    public class RSAUtils {

       /**
       * RSA公钥转换
       * @param publicKeyStr 公钥字符串
       * @return 公钥
       * @throws
       */
       public static PublicKey parsePublicKey(String publicKeyStr) throws InvalidKeySpecException {
       PublicKey publicKey = null;
       try {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        byte[] encodedKey = Base64.getDecoder().decode(publicKeyStr.getBytes(StandardCharsets.UTF_8));
        publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
       } catch (NoSuchAlgorithmException e) {
       }
       return publicKey;
       }

       /**
       * RSA私钥转换
       *
       * @param privateKeyStr 私钥字符串
       * @return 私钥
       * @throws
       */
       public static PrivateKey parsePrivateKey(String privateKeyStr) throws InvalidKeySpecException {
       PrivateKey privateKey = null;
       try {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        byte[] encodedKey = Base64.getDecoder().decode(privateKeyStr.getBytes(StandardCharsets.UTF_8));
        privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
       } catch (NoSuchAlgorithmException e) {
       }
       return privateKey;
       }

       /**
       * 签名(使用商户私钥)
       * @param data 待签名数据
       * @param privateKey 私钥
       * @return
       */
       public static String sign(String data, String privateKey) throws Exception {
       Signature signature = Signature.getInstance("SHA1withRSA");
       signature.initSign(parsePrivateKey(privateKey));
       signature.update(data.getBytes("UTF-8"));
       return new String(org.apache.commons.codec.binary.Base64.encodeBase64(signature.sign()));
       }

       /**
       * 验签(使用平台公钥)
       * @param data
       * @return
       * @throws Exception
       */
       public static boolean verify(JSONObject data) throws Exception {
       String sign = data.remove("sign").toString();
       Map<String,String> map = JSONObject.toJavaObject(data, Map.class);
       String signData = new TreeMap<>(map).entrySet().stream().filter(e -> StringUtils.isNotEmpty(e.getValue())).map(e -> e.getKey().concat("=").concat(e.getValue())).collect(Collectors.joining("&"));
       Signature signature = Signature.getInstance("SHA1withRSA");
       signature.initVerify(parsePublicKey(Const.PUBLIC_KEY));
       signature.update(signData.getBytes("UTF-8"));
       return signature.verify(org.apache.commons.codec.binary.Base64.decodeBase64(sign.getBytes("UTF-8")));
       }

    }

加密验签代码参考(PHP)

  • # 请求参数
    $arr["merchantId"] = Config::merchNo; //商户号
    $arr["version"] = Config::version; //版本号
    $arr["merchantOrderNo"] = date("YmdHis",time()).rand(1000,10000); //商户订单号
    $arr["amount"] = "100"; //金额 元
    $arr["bankCode"] = "ICBC";//银行代码
    $arr["bankcardAccountNo"] = "123456789";//银行卡号
    $arr["bankcardAccountName"] = "张三";//持卡人姓名
    $arr["notifyUrl"] = "https://baidu.com";//回调地址
    //排序
    ksort($arr);
    //拼接签名字符串
    $signData = ServiceUtil::get_sign($arr);

    //获取私钥
    $privateKey = ServiceUtil::privateKeyStr(Config::privateKey);
    //生成签名
    $sign = ServiceUtil::sign($signData,$privateKey);
    $arr["sign"] = $sign;
    $reqData = json_encode($arr, JSON_UNESCAPED_UNICODE);
    $result = ServiceUtil::curlPost(Config::remitUrl, $reqData);


    # 工具类(加密验签)
    header("Content-type:text/html;charset=utf8");

    class ServiceUtil
    {
       /**
       * 数组转为url字符串 过滤掉空值字段
       * $arr 数组
       */
       static function get_sign($arr)
       {
       $signmd5 = "";
       foreach ($arr as $x => $x_value) {
        if ($x_value == "0" || !empty($x_value)) {
         if ($signmd5 == "") {
          $signmd5 = $signmd5 . $x . '=' . $x_value;
         } else {
          $signmd5 = $signmd5 . '&' . $x . '=' . $x_value;
         }
        }
       }
       return $signmd5;
       }

       /**
       * 拼接公钥字符串
       *
       */
       static function publicKeyStr($publicStr)
       {
       //公钥
       $public_key = "-----BEGIN PUBLIC KEY-----\r\n";
       foreach (str_split($publicStr, 64) as $str) {
        $public_key .= $str . "\r\n";
       }
       $public_key .= "-----END PUBLIC KEY-----";
      
       return $public_key;
       }

       //拼接私钥字符串
       static function privateKeyStr($privatekey)
       {
       $private_key = "-----BEGIN PRIVATE KEY-----\r\n";
       foreach (str_split($privatekey, 64) as $str) {
        $private_key .= $str . "\r\n";
       }
       $private_key .= "-----END PRIVATE KEY-----";
      
       return $private_key;
       }

       /**
       * 平台公钥验签
       * @param $arr
       * @param $sign
       * @param $path
       * @return int
       * @throws Exception
       */
       static function verify($plainText, $sign, $path)
       {
       $resource = openssl_pkey_get_public($path);
       $result = openssl_verify($plainText, base64_decode($sign), $resource);
       openssl_free_key($resource);
       if (!$result) {
        return;
       }
       return $result;
       }

       /**
       * 商户私钥签名
       * @param $plainText
       * @param $path
       * @return string
       * @throws Exception
       */
       static function sign($plainText, $path)
       {
       try {
        $resource = openssl_pkey_get_private($path);
        $result = openssl_sign($plainText, $sign, $resource);
        openssl_free_key($resource);
       
        if (!$result) {
         return;
        }
        return base64_encode($sign);
       } catch (Exception $e) {
        return;
       }
       }

       //发起请求
       static function curlPost($url, $data)
       {
       $ch = curl_init();
       curl_setopt($ch, CURLOPT_URL, $url);
       curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
       curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
       curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
       curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
       curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
       curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
       curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
       curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
       curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
       $tmpInfo = curl_exec($ch);
       if (curl_errno($ch)) {
        return curl_error($ch);
       }
       return $tmpInfo;
       }
    }
Copyright@支付开放平台,lnc,All rights reserved.