侧边栏壁纸
博主头像
小城雨巷 博主等级

行动起来,活在当下

  • 累计撰写 20 篇文章
  • 累计创建 6 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

未命名文章

tengfei
2024-03-28 / 0 评论 / 0 点赞 / 28 阅读 / 0 字
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));
        }
    }

}


0

评论区