package com.siebre.itx.cebb.util;
import com.czb.commons.security.cipher.sm.SM2;
import com.czb.commons.security.cipher.sm.SM2KeyVO;
import com.siebre.itx.cebb.util.sm2.SM2Factory;
import com.siebre.itx.cebb.util.sm2.SM2Result;
import com.siebre.itx.cebb.util.sm2.SM2SignVO;
import com.siebre.itx.cebb.util.sm2.Util;
import org.bouncycastle.asn1.*;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.util.Arrays;
import java.util.Enumeration;
/**
* @author outengfei
* @date 2023/4/13 11:25
*/
public class CEBBSM2Util {
private final static int RS_LEN = 32;
/**
* 默认USERID
*/
public static String USER_ID = "1234567812345678";
/**
* 验证签名
*
* @param publicKey
* 公钥信息
* @param sourceData
* 密文信息
* @param signData
* 签名信息
* @return 验签的对象 包含了相关参数和验签结果
*/
@SuppressWarnings("unchecked")
public static SM2SignVO VerifySignSM2(byte[] publicKey, byte[] sourceData, byte[] signData) {
try {
byte[] formatedPubKey;
SM2SignVO verifyVo = new SM2SignVO();
verifyVo.setSm2_type("verify");
if (publicKey.length == 64) {
// 添加一字节标识,用于ECPoint解析
formatedPubKey = new byte[65];
formatedPubKey[0] = 0x04;
System.arraycopy(publicKey, 0, formatedPubKey, 1, publicKey.length);
} else {
formatedPubKey = publicKey;
}
SM2Factory factory = SM2Factory.getInstance();
ECPoint userKey = factory.ecc_curve.decodePoint(formatedPubKey);
SM3Digest sm3Digest = new SM3Digest();
byte[] z = factory.sm2GetZ(USER_ID.getBytes(), userKey);
//System.out.println("SM3摘要Z: " + Util.getHexString(z));
verifyVo.setSm3_z(Util.getHexString(z));
sm3Digest.update(z, 0, z.length);
sm3Digest.update(sourceData, 0, sourceData.length);
byte[] md = new byte[32];
sm3Digest.doFinal(md, 0);
//System.out.println("SM3摘要值: " + Util.getHexString(md));
verifyVo.setSm3_digest(Util.getHexString(md));
ByteArrayInputStream bis = new ByteArrayInputStream(signData);
ASN1InputStream dis = new ASN1InputStream(bis);
SM2Result sm2Result = null;
ASN1Primitive derObj = dis.readObject();
Enumeration<ASN1Integer> e = ((ASN1Sequence) derObj).getObjects();
BigInteger r = ((ASN1Integer) e.nextElement()).getValue();
BigInteger s = ((ASN1Integer) e.nextElement()).getValue();
sm2Result = new SM2Result();
sm2Result.r = r;
sm2Result.s = s;
//System.out.println("vr: " + sm2Result.r.toString(16));
//System.out.println("vs: " + sm2Result.s.toString(16));
verifyVo.setVerify_r(sm2Result.r.toString(16));
verifyVo.setVerify_s(sm2Result.s.toString(16));
factory.sm2Verify(md, userKey, sm2Result.r, sm2Result.s, sm2Result);
boolean verifyFlag = sm2Result.r.equals(sm2Result.R);
verifyVo.setVerify(verifyFlag);
return verifyVo;
} catch (IllegalArgumentException e) {
e.printStackTrace();
System.out.println("验签失败");
return null;
} catch (Exception e) {
// LcptLog.getTransLogNoCache().error("验签失败",e);
e.printStackTrace();
System.out.println("验证签名失败");
return null;
}
}
/**
* 私钥签名 使用SM3进行对明文数据计算一个摘要值
*
* @param privatekey
* 私钥
* @param sourceData
* 明文数据
* @return 签名后的值
* @throws Exception
*/
public static SM2SignVO Sign2SM2(byte[] privatekey, byte[] sourceData) throws Exception {
SM2SignVO sm2SignVO = new SM2SignVO();
sm2SignVO.setSm2_type("sign");
SM2Factory factory = SM2Factory.getInstance();
BigInteger userD = new BigInteger(privatekey);
// System.out.println("userD:"+userD.toString(16));
sm2SignVO.setSm2_userd(userD.toString(16));
ECPoint userKey = factory.ecc_point_g.multiply(userD);
// System.out.println("椭圆曲线点X: "+ userKey.getXCoord().toBigInteger().toString(16));
// System.out.println("椭圆曲线点Y: "+ userKey.getYCoord().toBigInteger().toString(16));
SM3Digest sm3Digest = new SM3Digest();
byte[] z = factory.sm2GetZ(USER_ID.getBytes(), userKey);
// System.out.println("SM3摘要Z: " + Util.getHexString(z));
// System.out.println("被加密数据的16进制: " + Util.getHexString(sourceData));
sm2SignVO.setSm3_z(Util.getHexString(z));
sm2SignVO.setSign_express(Util.getHexString(sourceData));
sm3Digest.update(z, 0, z.length);
sm3Digest.update(sourceData, 0, sourceData.length);
byte[] md = new byte[32];
sm3Digest.doFinal(md, 0);
// System.out.println("SM3摘要值: " + Util.getHexString(md));
sm2SignVO.setSm3_digest(Util.getHexString(md));
SM2Result sm2Result = new SM2Result();
factory.sm2Sign(md, userD, userKey, sm2Result);
// System.out.println("r: " + sm2Result.r.toString(16));
// System.out.println("s: " + sm2Result.s.toString(16));
sm2SignVO.setSign_r(sm2Result.r.toString(16));
sm2SignVO.setSign_s(sm2Result.s.toString(16));
ASN1Integer d_r = new ASN1Integer(sm2Result.r);
ASN1Integer d_s = new ASN1Integer(sm2Result.s);
ASN1EncodableVector v2 = new ASN1EncodableVector();
v2.add(d_r);
v2.add(d_s);
DERSequence sign = new DERSequence(v2);
String result = Util.byteToHex(sign.getEncoded());
sm2SignVO.setSm2_sign(result);
return sm2SignVO;
}
/**
* BC的SM3withSM2验签需要的rs是asn1格式的,这个方法将直接拼接r||s的字节数组转化成asn1格式
* @param sign in plain byte array
* @return rs result in asn1 format
*/
public static byte[] rsPlainByteArrayToAsn1(byte[] sign){
if(sign.length != RS_LEN * 2) throw new RuntimeException("err rs. ");
BigInteger r = new BigInteger(1, Arrays.copyOfRange(sign, 0, RS_LEN));
BigInteger s = new BigInteger(1, Arrays.copyOfRange(sign, RS_LEN, 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);
}
}
/**
* BC的SM3withSM2签名得到的结果的rs是asn1格式的,加密机需要直接拼接r||s的字节数组,使用这个方法转换
* @param rsDer rs in asn1 format
* @return sign result in plain byte array
*/
public static byte[] 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());
byte[] result = new byte[RS_LEN * 2];
System.arraycopy(r, 0, result, 0, r.length);
System.arraycopy(s, 0, result, RS_LEN, s.length);
return result;
}
//生成随机秘钥对
public static SM2KeyVO generateKeyPair(){
SM2 sm2 = SM2.Instance();
AsymmetricCipherKeyPair key = null;
while (true){
key=sm2.ecc_key_pair_generator.generateKeyPair();
if(((ECPrivateKeyParameters) key.getPrivate()).getD().toByteArray().length==32){
break;
}
}
ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();
ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();
BigInteger privateKey = ecpriv.getD();
ECPoint publicKey = ecpub.getQ();
SM2KeyVO sm2KeyVO = new SM2KeyVO();
sm2KeyVO.setPublicKey(publicKey);
sm2KeyVO.setPrivateKey(privateKey);
System.out.println("公钥: " + Util.byteToHex(publicKey.getEncoded(false)).toUpperCase());
System.out.println("私钥: " + Util.byteToHex(privateKey.toByteArray()).toUpperCase());
return sm2KeyVO;
}
/**
* SM2算法生成密钥对
* @return 密钥对信息
*/
public static KeyPair generateSm2KeyPair() {
try {
final ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");
// 获取一个椭圆曲线类型的密钥对生成器
final KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
SecureRandom random = new SecureRandom();
// 使用SM2的算法区域初始化密钥生成器
kpg.initialize(sm2Spec, random);
// 获取密钥对
KeyPair keyPair = kpg.generateKeyPair();
PublicKey aPublic = keyPair.getPublic();
PrivateKey aPrivate = keyPair.getPrivate();
String publicKeyHex = Hex.toHexString(((BCECPublicKey) aPublic).getQ().getEncoded(false));
String privateKeyHex = ((BCECPrivateKey) aPrivate).getD().toString(16);
System.out.println("公钥: " + publicKeyHex.toUpperCase());
System.out.println("私钥: " + privateKeyHex.toUpperCase());
return keyPair;
} catch (Exception e) {
//LOGGER.error("generate sm2 key pair failed:{}", e.getMessage(), e);
//throw new BusinessException("生成密钥对失败");
}
return null;
}
private static byte[] bigIntToFixexLengthBytes(BigInteger rOrS){
// for sm2p256v1, n is 00fffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123,
// r and s are the result of mod n, so they should be less than n and have length<=32
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));
}
}
}
版权归属:
tengfei
许可协议:
本文使用《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》协议授权
评论区