全部
全部
更新时间:2023-12-14 17:05:29
功能接口调用

(1)接入方生成SM2公私钥对(公私钥对生成方法见下文),签名公钥录入至开放平台“个人中心-API认证账号-SM2验签公钥(SM2-VerifyPublicKey) ”(需要用户先登录开放平台),签名私钥SignPrivateKey用来计算签名。调用接口时,请提前将服务器IP地址添加到用户IP白名单中,否则将无法调用,返回应答码为9901(详见:全局返回码说明)。



(2)使用请求头部信息和、SM2签名私钥SignPrivateKey计算得出签名信息sign。

         签名规则:

            a. 将请求头部信息的version、appid、bizMethod、reqId和请求报文body以&作为连接符拼接成待签名串, 型如:

                "version=[version]&appId=[appId]&bizMethod= [bizMethod]&reqId=[reqId]&body=[body]";

            b. 对待签名串使用SM3做摘要(SM3摘要算法见下文);

            c. 用SignPrivateKey对摘要做SM2签名(SM2签名算法见下文),得到签名信息sign。

                     SignPrivateKey: SM2签名私钥;

                     body: 请求JSON报文;



(3)使用API认证账号AppId、签名信息sign、请求头部信息header、请求报文body,发出API调用请求。

    HTTP 请求方式:

        POST



    HTTP URL:

        https://openapi.unionpay.com/upapi/cardbin/cardinfo


    HTTP 报文头(header):

        Content-Type: application/json

    其余参数请参考下表:

中文名称

英文名称

域类型

域长度

默认值

请求要求

备注

版本号

version

string

8


M-必填

格式xx.yy.zz

取值举例1.0.0

发送方索引类型

appType

string

2


M-必填

取值:

00:银联索引

01:机构索引

02:商户索引

发送方索引标识码 

appId

string

32


M-必填

由银联分配,请求或应答的发送方填写,标识签名验签对应的发送方

接口类型

bizMethod

string

64


M-必填

取值:宜全英文,不应出现中文

取值举例:cardbin.cardinfo

签名

sign

string

344


M-必填

根据报文签名方法生成对报文摘要的签名

签名或摘要方式

signMethod

string

20


M-必填

取值:

1RSA2

2SM2

发送方流水号

reqId

string

64


M-必填

请求方自行生成,保证每笔交易不重复,但非交易主键


     HTTP 报文体(body):

              JSON格式接口请求报文,如{"cardNo":""}


(4)API接口的请求参数、应答参数依据业务需求会配置校验规则或加解密规则,相关内容请参考《参数规则说明


接入方公私钥对生成方法

引用jar包:


<dependency>

    <groupId>org.bouncycastle</groupId>

    <artifactId>bcprov-jdk15on</artifactId>

    <version>1.60</version>

    <type>jar</type>

</dependency>


生成公私钥对象:


/** 需要导入包 */

import org.bouncycastle.jce.provider.BouncyCastleProvider;

/**转化长度*/

private final static int RS_LEN = 32;

/**获取SM2椭圆曲线推荐参数*/

private static X9ECParameters x9ECParameters =GMNamedCurves.getByName("sm2p256v1");

/**构建EC算法参数*/

private static ECParameterSpec ecParameterSpec = new ECParameterSpec(

        x9ECParameters.getCurve(),/**设置曲线方程*/

        x9ECParameters.getG(), /**椭圆曲线G点*/

        x9ECParameters.getN());/**大整数N*/

static {

      if (Security.getProvider("BC") == null) {

        Security.addProvider(new BouncyCastleProvider());

     } else {

        Security.removeProvider("BC");

        Security.addProvider(new BouncyCastleProvider());

      }

}

/**

     *  生成公私钥对象

     *

     * @return

     */

public static KeyPair generateKeyPair() {

    try {

          KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC");

          kpGen.initialize(ecParameterSpec, new SecureRandom());

          KeyPair kp = kpGen.generateKeyPair();

          return kp;

      } catch (Exception e) {

        throw new RuntimeException(e);

      }

}



公私钥对象转换并获得私钥和公钥字符串,转换方法如下:


/**私钥字符串,为了签名用*/

String priKey = new BASE64Encoder().encode(kp.getPrivate().getEncoded()); 

 

/** 公钥字符串pubKey,为了后续验签用 */

SM2PublicKey sm2PublicKey = new SM2PublicKey();

        sm2PublicKey.setBits(256);

   sm2PublicKey.setX(((BCECPublicKey)kp.getPublic()).getQ().getXCoord().getEncoded());

   sm2PublicKey.setY(((BCECPublicKey)kp.getPublic()).getQ().getYCoord().getEncoded());

String pubKey = Base64.encodeBase64String(JSONObject.toJSONString(sm2PublicKey).getBytes());

/**

 * 公钥数据结构

 */

public class SM2PublicKey {

    public int bits;

    public byte[]x = new byte[32];

    public byte[] y = new byte[32];

    public SM2PublicKey() {

    }

    public int getBits() {

        return bits;

    }

    public void setBits(int bits) {

        this.bits = bits;

    }

    public byte[] getX() {

        return x;

    }

    public void setX(byte[] x) {

        this.x = x;

    }

    public byte[] getY() {

        return y;

    }

    public void setY(byte[] y) {

        this.y = y;

    }

}


报文签名样例代码


SM2非对称认证方式报文签名规则-Java语言


/**

 * SM2非对称认证方式签名算法

 * @param body 请求报文体

 * @param SignPrivateKey  SM2签名私钥

 */

public static String getSM2Sign(String body,String SignPrivateKey,String version,String appId,String bizMethod,String reqId){

//获得私钥对象

byte[] prvBytes22 = new BASE64Decoder().decodeBuffer(SignPrivateKey);

PKCS8EncodedKeySpec eks2 = new PKCS8EncodedKeySpec(prvBytes22);

KeyFactory kf22 = KeyFactory.getInstance("EC", "BC");

PrivateKey pvk = kf22.generatePrivate(eks2);

// 拼接待签名字符串,计算SM3摘要

String originalStr = "version="+version+"&appId="+appId+"&bizMethod="+bizMethod+"&reqId="+reqId+"&body="+body;

  String signForVerify = sm3X16Str(originalStr, "UTF-8");

  String realSign = null;

  try {

    // 对摘要做sm2签名

    SM2Signature sm2Signature= signSm3WithSm2(signForVerify.getBytes(),userId, pvk);

 realSign= Base64.encodeBase64String(JSONObject.toJSONString(sm2Signature).getBytes());

  } catch (Exception e) {

     e.printStackTrace();

   }

   return realSign;

}


SM3摘要算法实现样例-Java语言


/**

     * sm3计算后进行16进制转换

     * @param data     待签字符串

     * @param encoding 编码

     * @return 计算结果

     */

public static String sm3X16Str(String data, String encoding){

   byte[] bytes = sm3(data, encoding);

   StringBuilder sm3StrBuff = new StringBuilder();

   for (int i = 0; i < bytes.length; i++) {

     if (Integer.toHexString(0xFF & bytes[i]).length() == 1) {

        sm3StrBuff.append("0").append(Integer.toHexString(0xFF & bytes[i]));

     } else {

           sm3StrBuff.append(Integer.toHexString(0xFF & bytes[i]));

          }

     }

     return sm3StrBuff.toString();

  }


/**

     * sm3计算

     * @param datas    待计算的数据

     * @param encoding 字符集编码

     * @return

     */

private static byte[] sm3(String datas, String encoding) {

  try {

     SM3Digest sm3 = new SM3Digest();

    byte[] bytes = datas.getBytes(encoding);

     sm3.update(bytes, 0, bytes.length);

     byte[] result = new byte[sm3.getDigestSize()];

     sm3.doFinal(result, 0);

    return result;

  } catch (UnsupportedEncodingException e) {

    return null;

   }

 }


SM2签名算法实现样例-Java语言



/**固定值 */

byte[] userId = "1234567812345678".getBytes();

/**

     * SM2签名

     * @param msg 待签字符串(SM3计算后)

     * @param userId 用户id

     * @param privateKey 私钥

     * @return r||s,直接拼接byte数组的rs

     */

public static SM2Signature signSm3WithSm2(byte[] msg, byte[] userId, PrivateKey privateKey) {

     return rsAsn1ToPlainByteArray(signSm3WithSm2Asn1Rs(msg, userId, privateKey));

 }

/**

     * 获得签名字段值

     * @param msg 待签字符串

     * @param userId 用户id

     * @param privateKey 私钥

     * @return rs in <b>asn1 format</b>

     */

public static byte[] signSm3WithSm2Asn1Rs(byte[] msg, byte[] userId,PrivateKey privateKey) {

   try {

         SM2ParameterSpec parameterSpec = new SM2ParameterSpec(userId);

         Signature signer = Signature.getInstance("SM3withSM2", "BC");

         signer.setParameter(parameterSpec);

         signer.initSign(privateKey, new SecureRandom());

        signer.update(msg, 0, msg.length);

         byte[] sig = signer.sign();

       return sig;

       }catch (Exception e) {

          throw new RuntimeException(e);

       }

    }

/**

     * BC的SM3withSM2签名得到的结果的rs是asn1格式的,这个方法转化成直接拼接r||s, 并存入SM2Signature对象中

     * @param rsDer rs in asn1 format

     * @return sign result in plain byte array

     */

public static SM2Signature rsAsn1ToPlainByteArray(byte[] rsDer) {

       ASN1Sequence seq = ASN1Sequence.getInstance(rsDer);

       byte[] r = bigIntToFixexLengthBytes(ASN1Integer.getInstance(seq.getObjectAt(0)).getValue());

       byte[] s = bigIntToFixexLengthBytes(ASN1Integer.getInstance(seq.getObjectAt(1)).getValue());

       SM2Signature sm2Signature = new SM2Signature();

            sm2Signature.setR(r);

            sm2Signature.setS(s);

     return sm2Signature;

}

 

/**

     * 转换方法

     * @param rOrS

     * @return

     */

public static byte[] bigIntToFixexLengthBytes(BigInteger rOrS) {

     byte[] rs = rOrS.toByteArray();

     if (rs.length== RS_LEN) return rs;

     else if (rs.length== RS_LEN + 1 && rs[0] == 0)

return Arrays.copyOfRange(rs, 1, RS_LEN + 1);

     else if (rs.length < RS_LEN) {

           byte[] result = new byte[RS_LEN];

           Arrays.fill(result, (byte) 0);

           System.arraycopy(rs, 0, result, RS_LEN - rs.length, rs.length);

           return result;

      } else {

          throw new RuntimeException("err rs: " + Hex.toHexString(rs));

         }

    }

 

/**

 * SM2Sign数据结构

 */

public class SM2Signature {

    public byte[] r = new byte[32];

    public byte[] s = new byte[32];

    public SM2Signature() {

    }

    public byte[] getR() {

        return r;

    }

    public void setR(byte[] r) {

        this.r = r;

    }

    public byte[] getS() {

        return s;

    }

    public void setS(byte[] s) {

        this.s = s;

    }

}


咨询服务