关于SM2加密验签的操作

 对接银行的统一收单系统,用到SM2加密验签流程:

 1:统一收单系统对接平台商户需要向CFCA申请复合证书,一个用于商户签名,另外一个用于报文加密

 2:平台商户入驻成功后,证书通过商户pc端自助申请和下载

用到的工具包:SADK(SADK(Security Application Development Kit)是CFCA推出的一套支持全平台、全浏览器、多语言的安全应用开发套件。实现了证书下载、证书应用过程中的全业务功能覆盖,可与客户业务系统、CFCA RA、CA、统一下载平台无缝对接,为用户提供证书下载、证书更新、签名验签、加密解密等全方位的数字证书安全服务)

 CFCA加验签方式用的是非对称加密,私钥加签,公钥验签。请求时用自己证书的私钥加签,银行用我们公钥验签。响应时银行用银行私钥加签,我们用银行公钥验签。
不论什么证书,加验签一定是自己的私钥加签,公钥提供出去进行对应的私钥验签。证书对应的是两个证书,我们有一个证书,银行也有一个证书,这两张证书相对独立的,自己用自己的,只是交换了证书公钥进行验证

 对接银行需要获得的一些数据:1:sm2结尾的证书 2:证书密钥  3:对银行返回签名串进行验签的公钥 

 具体操作:1:调银行接口生成的加签签名串,以私钥D进行加签,公钥的X和Y进行自行验签  2:对银行返回的签名串,以银行公钥X和Y进行验签。其中特别注意的是,银行返回的签名串是128位的,进行公钥初始化的时候,要把公钥的进行16位的转码,byte[] encPub = Hex.decode(PUB_KEY),否则初始化失败  3:获得证书序列号时,有十进制证书序列号 x509Cert.getSerialNumber()和十六进制证书序列号x509Cert.getStringSerialNumber()的区别,本文选用十六进制

注意:提前引入 SADK包,下面方法直接引用 SADK包里面的即可

public class Sm2Test {

    //待签名串
    private static final String signData = "3002 2939993 230302";
    //证书密码
    private static final String SM2Password = "证书密码";
    //商户证书路径
    private static final String SM2File = "本地商户证书路径";
    //公钥X
    private static String X = "";
    //公钥Y
    private static String Y = "";
    //私钥D
    private static String D = "";
    //获取16位CACA证书序列号
    private static String CERT_NUM = "";
    //银行给的128位公钥数据
    private static String PUB_KEY = "银行给到的公钥";
    //银行返回的签名
    private static final String signatureBack = "银行返回的签名串";
    //银行的返回数据组装的签名串
    private static final String signDataBack = "根据银行加签验签规则组装的签名串";

    public static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }

    static {
        try {
            // 初始化SM2私钥和证书
            byte[] SM2Data = Base64.decode(FileHelper.read(SM2File));
            PrivateKey SM2PrivateKey = KeyUtil.getPrivateKeyFromSM2(SM2Data, SM2Password);
            X509Cert x509Cert = CertUtil.getCertFromSM2(SM2Data);


            GMTPrivateKey gMTPrivateKey = (GMTPrivateKey) SM2PrivateKey;
            GMTPublicKey gMTPublicKey = gMTPrivateKey.getSM2PublicKey();

            D = new String(Hex.encode(gMTPrivateKey.getDByBytes())).toLowerCase();
            X = gMTPublicKey.getQ().getXCoord().toString();
            Y = gMTPublicKey.getQ().getYCoord().toString();

            CERT_NUM = x509Cert.getStringSerialNumber();

            System.out.println("获取d:" + D);
            System.out.println("获取x:" + X);
            System.out.println("获取y:" + Y);
            System.out.println("证书序列号:" + CERT_NUM);

        } catch (Exception e) {
            System.out.println("加载证书异常:" + e);
        }
    }

    public static void main(String[] args) {
        //厂商加签传给银行
        sm2Sign();
        //进行银行返回验签
        sm2Verify();
    }

    //加签
    public static void sm2Sign() {
        SM2 clz = SM2.getInstance();
        byte[] sign = clz.SM2Sign(SM2Demo.hexStringToBytes(D), signData.getBytes());
        String signature = new String(sign);
        System.out.println("加签的签名串:" + signature);
        boolean verify = clz.SM2Verify(hexStringToBytes(X), hexStringToBytes(Y), signData.getBytes(), sign);
        System.out.println("自行验签:" + verify);
    }

    //验签
    public static void sm2Verify() {
        SM2 clz = SM2.getInstance();
        byte[] encPub = Hex.decode(PUB_KEY);
        GMTPublicKey gmtPublicKey = new GMTPublicKey(encPub);
        X = gmtPublicKey.getQ().getXCoord().toString();
        Y = gmtPublicKey.getQ().getYCoord().toString();

        boolean verify2 = clz.SM2Verify(hexStringToBytes(X), hexStringToBytes(Y), signDataBack.getBytes(), signatureBack.getBytes());
        System.out.println("回调验签结果:" + verify2);
    }


    public static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }

        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return d;
    }


}

  运行结果如下图,加签,自行验签,回调验签都正常。则SM2加解密完美完成

关于SM2加密验签的操作_第1张图片

你可能感兴趣的:(工具类,java,加密解密)