1
zhujie
5 天以前 ec15861e14c66c38b1a8f5fffc6975d7da6c315c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package com.mzl.flower.pay;
 
import java.io.IOException;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
 
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.jcajce.spec.SM2ParameterSpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
 
public class SmUtil {
    static{
        Security.addProvider(new BouncyCastleProvider());
    }
    /**算法常量:SM3withSM2*/
    public static final String ALGORITHM_SM3SM2_BCPROV = "SM3withSM2";
    private final static int SM3withSM2_RS_LEN=32;
 
    public static void main(String[] args) throws Exception {
        /**商户平台分配的appid,也是签名的certid**/
        String appid = "00000156";
        /**商户sm2私钥,用于向通联发起请求前进行签名**/
        String cusPrivateKey = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgjj4Rk+b0YjwO+UwXofnHf4bK+kaaY5Btkd8nMP2VimmgCgYIKoEcz1UBgi2hRANCAAQqlALW4qGC3bP1x3wo5QsKxaCMEZJ2ODTTwOQ+d8UGU7GoK/y/WMBQWf5upMnFU06p5FxGooXYYoBtldgm03hq";
        /**商户sm2公钥,需要配置到通联商户平台**/
        String cusPubKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEKpQC1uKhgt2z9cd8KOULCsWgjBGSdjg008DkPnfFBlOxqCv8v1jAUFn+bqTJxVNOqeRcRqKF2GKAbZXYJtN4ag==";
        
        /**通联平台sm2公钥,用于请求返回或者通联通知的验签**/
        String tlPubKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE/BnA8BawehBtH0ksPyayo4pmzL/u1FQ2sZcqwOp6bjVqQX4tjo930QAvHZPJ2eez8sCz/RYghcqv4LvMq+kloQ==";
        
        String blankStr = "请求待签名数据";
        PrivateKey privkey = privKeySM2FromBase64Str(cusPrivateKey);
        String sign = signSM3SM2RetBase64(privkey, appid, blankStr.getBytes("UTF-8"));//签名
        System.out.println(sign);
        
        String rspBlankStr = "返回待验签数据";//通联返回的明文
        String rspSign = "AovBKQGUe0xuJ0ox7FgIIX+yB3DzbudgUsnNvJmDV0IdHZtU2Y8vdeUY1pd2vmPUf08hNgdkoz+4WP/D/ktOcA==";//通联返回的签名
        PublicKey publicKey = pubKeySM2FromBase64Str(tlPubKey);
        boolean isOk = verifySM3SM2(publicKey, "Allinpay", Base64.decodeBase64(rspSign), rspBlankStr.getBytes("UTF-8"));
        System.out.println("验签结果:"+isOk);
        
 
    }
    
    /**签名并BASE64编码-SM3WithSM2 */
    public static String signSM3SM2RetBase64(final PrivateKey privateKey,String certid,final byte[] data) throws Exception{
        return Base64.encodeBase64String(signSM3SM2(privateKey, certid, data));
    }
    
    /**签名-SM3WithSM2 */
    public static byte[] signSM3SM2(final PrivateKey privateKey,String certid,final byte[] data) throws Exception{
        SM2ParameterSpec parameterSpec = new SM2ParameterSpec(certid.getBytes());
        Signature signer = Signature.getInstance(ALGORITHM_SM3SM2_BCPROV, "BC");
        signer.setParameter(parameterSpec);
        signer.initSign(privateKey, new SecureRandom());
        signer.update(data);
        return byteAsn12BytePlain(signer.sign());
    }
    
    /** 验证签名-SM3WithSM2*/
    public static boolean verifySM3SM2(final PublicKey publicKey,String certid,final byte[] signData, final byte[] srcData) throws Exception {
        SM2ParameterSpec parameterSpec = new SM2ParameterSpec(certid.getBytes());
        Signature verifier = Signature.getInstance(ALGORITHM_SM3SM2_BCPROV, "BC");
        verifier.setParameter(parameterSpec);
        verifier.initVerify(publicKey);
        verifier.update(srcData);
        return verifier.verify(bytePlain2ByteAsn1(signData));
    }
    
    /**从字符串读取私钥-目前支持PKCS8(keystr为BASE64格式)*/
    public static PrivateKey privKeySM2FromBase64Str(String keystr) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance("EC");
        return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(Base64.decodeBase64(keystr)));
    }
    
    /**从字符串读取RSA公钥(keystr为BASE64格式)*/
    public static PublicKey pubKeySM2FromBase64Str(String keystr) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance("EC");
        return keyFactory.generatePublic(new X509EncodedKeySpec(Base64.decodeBase64(keystr)));
    }
    
    /**
     * 将普通字节数组转换为ASN1字节数组 适用于SM3withSM2验签时验签明文转换
     */
    private static byte[] bytePlain2ByteAsn1(byte[] data) {
        if (data.length != SM3withSM2_RS_LEN * 2) throw new RuntimeException("err data. ");
        BigInteger r = new BigInteger(1, Arrays.copyOfRange(data, 0, SM3withSM2_RS_LEN));
        BigInteger s = new BigInteger(1, Arrays.copyOfRange(data, SM3withSM2_RS_LEN, SM3withSM2_RS_LEN * 2));
        ASN1EncodableVector v = new ASN1EncodableVector();
        v.add(new ASN1Integer(r));
        v.add(new ASN1Integer(s));
        try {
            return new DERSequence(v).getEncoded("DER");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 将ASN1字节数组转换为普通字节数组 适用于SM3withSM2签名时签名结果转换
     */
    private static byte[] byteAsn12BytePlain(byte[] dataAsn1) {
        ASN1Sequence seq = ASN1Sequence.getInstance(dataAsn1);
        byte[] r = bigIntToFixexLengthBytes(ASN1Integer.getInstance(seq.getObjectAt(0)).getValue());
        byte[] s = bigIntToFixexLengthBytes(ASN1Integer.getInstance(seq.getObjectAt(1)).getValue());
        byte[] result = new byte[SM3withSM2_RS_LEN * 2];
        System.arraycopy(r, 0, result, 0, r.length);
        System.arraycopy(s, 0, result, SM3withSM2_RS_LEN, s.length);
        return result;
    }
    
    private static byte[] bigIntToFixexLengthBytes(BigInteger rOrS) {
        byte[] rs = rOrS.toByteArray();
        if (rs.length == SM3withSM2_RS_LEN) return rs;
        else if (rs.length == SM3withSM2_RS_LEN + 1 && rs[0] == 0)
            return Arrays.copyOfRange(rs, 1, SM3withSM2_RS_LEN + 1);
        else if (rs.length < SM3withSM2_RS_LEN) {
            byte[] result = new byte[SM3withSM2_RS_LEN];
            Arrays.fill(result, (byte) 0);
            System.arraycopy(rs, 0, result, SM3withSM2_RS_LEN - rs.length, rs.length);
            return result;
        } else {
            throw new RuntimeException("err rs: " + Hex.toHexString(rs));
        }
    }
 
}