闲碎记事本 闲碎记事本
首页
  • JAVA
  • Cloudflare
  • 学完再改一遍UI
友链
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

YAN

我要偷偷记录...
首页
  • JAVA
  • Cloudflare
  • 学完再改一遍UI
友链
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • java

    • SpringBoot

    • SpringSecurity

    • MybatisPlus

    • Netty

    • sip

      • SIP使用
      • GB28181
      • GB35114
      • SM2工具类
        • SM3工具类
        • 证书构建
        • 使用注解实现XML构建与解析
        • 流媒体服务器
        • FFmpeg
      • 其他

    • linux

    • docker

    • redis

    • nginx

    • mysql

    • 其他

    • 环境搭建

    • 知识库
    • java
    • sip
    YAN
    2024-07-26
    目录

    SM2工具类

    GB35114 SM2 封装 ,基于 bouncycastle 和 hutool-crypto

    # 导入依赖

    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcpkix-jdk18on</artifactId>
        <version>1.78.1</version>
    </dependency>
    
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-crypto</artifactId>
        <version>5.8.24</version>
    </dependency>
    

    # 说明

    GB35114 签名示例
    SIGN1 示例: SM2(random2+random1+ serverid)
    SIGN2 示例: SM2(random1+random2+deviceid+cryptkey)
    其中 cryptkey: encodeBase64(encodeAsn1(encryptSM2(vkek)))

    # Sm2Util

    查看代码
    
            
    @Slf4j
    public class Sm2Util {
    
        private static SM2 sm2;
        
        /**
         * 初始化
         * @param pub 16进制公钥
         * @param pir 16进制私钥
         */
        public static void init(String pub, String pir) {
            if(StrUtil.isBlankIfStr(pub) || StrUtil.isBlankIfStr(pir)){
                return;
            }
            ECPrivateKeyParameters pr = BCUtil.toSm2Params(pir);
            ECPublicKeyParameters pu =  BCUtil.toSm2Params(pub.substring(0, 64), pub.substring(64, 128));
            sm2 = new SM2(pr,pu);
        }
        
        /**
         * 签名
         * @param data 加密数据
         * @return 签名
         */
        public static String sign(String data) {
            byte[] sign = sm2.sign(data.getBytes(StandardCharsets.UTF_8));
            return Base64.encode(sign);
        }
    
        /**
         * 验签
         * @param data 签名后的数据
         * @param sign 签名
         * @return 是否验证通过
         */
        public static boolean verify(String data, String sign) {
            byte[] decode = Base64.decode(sign);
            return sm2.verify(data.getBytes(StandardCharsets.UTF_8),decode);
        }
    
        /**
         * 验签
         * @param data 签名后的数据
         * @param sign 签名
         * @param publicKey 对方公钥
         * @return 是否验证通过
         */
        public static boolean verify(String data, String sign, PublicKey publicKey) {
            if(null == publicKey){
                return false;
            }
            SM2 sm2 = new SM2(null,publicKey);
            byte[] decode = Base64.decode(sign);
            return sm2.verify(data.getBytes(StandardCharsets.UTF_8),decode);
        }
    
    
    
        /**
         * 加密
         * @param data 原数据
         * @return 加密字符
         */
        public static String encrypt(String data) {
            try {
                //得到加密前数据byte
                byte[] bytes = data.getBytes(StandardCharsets.UTF_8);
                //得到原始密文
                byte[] encrypt = sm2.encrypt(bytes);
                //为原始密文添加 ASN1 编码
                byte[] asn1byte = encodeAsn1Cipher(encrypt, SM2Engine.Mode.C1C3C2);
                return Base64.encode(asn1byte);
            } catch (Exception e) {
                throw  new RuntimeException("信息加密失败,请检查秘钥",e);
            }
        }
    
        /**
         * 加密
         * @param data 原数据
         * @return 加密字符
         */
        public static String encrypt(String data,PublicKey publicKey) {
            try {
                byte[] bytes = data.getBytes(StandardCharsets.UTF_8);
                SM2 sm2 = new SM2(null,publicKey);
                byte[] encrypt = sm2.encrypt(bytes);
                return Base64.encode(encrypt);
            } catch (Exception e) {
                throw  new RuntimeException("信息加密失败,请检查秘钥",e);
            }
        }
    
    
    
        /**
         * 解密
         * @param cipherText 密文
         * @return 解密字符
         */
        public static String decrypt(String cipherText) {
            try {
                //base 解码数据
                byte[] decode = Base64.decode(cipherText);
                //解码 ASN1 编码的密文
                byte[] data = decodeAsn1Cipher(decode, SM2Engine.Mode.C1C3C2);
                //解码原密文
                byte[] bytes  = sm2.decrypt(data);
                return new String(bytes, StandardCharsets.UTF_8);
            } catch (Exception e) {
                throw  new RuntimeException("信息解密失败",e);
            }
        }
    
        /**
         * SM2 标准曲线
         */
        private static final X9ECParameters X9_EC_PARAMETERS = GMNamedCurves.getByName("sm2p256v1");
    
        /**
         * 解码 ASN1 编码的密文
         * @param asn1Cipher DER 编码的密文
         * @return 原始密文
         */
        public static byte[] decodeAsn1Cipher(byte[] asn1Cipher, SM2Engine.Mode mode) {
            ASN1Sequence sequence;
            try {
                sequence = (ASN1Sequence) DERSequence.fromByteArray(asn1Cipher);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            BigInteger x = ASN1Integer.getInstance(sequence.getObjectAt(0)).getPositiveValue();
            BigInteger y = ASN1Integer.getInstance(sequence.getObjectAt(1)).getPositiveValue();
            byte[] c1 = X9_EC_PARAMETERS.getCurve().validatePoint(x, y).getEncoded(false);
    
            byte[] c2, c3;
            if (mode == SM2Engine.Mode.C1C3C2) {
                c3 = ((ASN1OctetString) sequence.getObjectAt(2)).getOctets();
                c2 = ((ASN1OctetString) sequence.getObjectAt(3)).getOctets();
            } else {
                c2 = ((ASN1OctetString) sequence.getObjectAt(2)).getOctets();
                c3 = ((ASN1OctetString) sequence.getObjectAt(3)).getOctets();
            }
    
            byte[] plainCipher = new byte[c1.length + c2.length + c3.length];
            System.arraycopy(c1, 0, plainCipher, 0, c1.length);
            if (mode == SM2Engine.Mode.C1C3C2) {
                System.arraycopy(c3, 0, plainCipher, c1.length, c3.length);
                System.arraycopy(c2, 0, plainCipher, c1.length + c3.length, c2.length);
            } else {
                System.arraycopy(c2, 0, plainCipher, c1.length, c2.length);
                System.arraycopy(c3, 0, plainCipher, c1.length + c2.length, c3.length);
            }
            return plainCipher;
        }
    
    
        /**
         * 为原始密文添加 ASN1 编码
         *
         * @param plainCipher 原始密文
         * @return ASN1 编码的格式的密文
         */
        public static byte[] encodeAsn1Cipher(byte[] plainCipher, SM2Engine.Mode mode) {
            // sm2p256v1 的这个固定 65。可以看 GMNamedCurves、ECCurve 代码
            final int c1Len = (X9_EC_PARAMETERS.getCurve().getFieldSize() + 7) / 8 * 2 + 1;
            byte[] c1 = new byte[c1Len];
            System.arraycopy(plainCipher, 0, c1, 0, c1Len);
    
            BigInteger x = X9_EC_PARAMETERS.getCurve().decodePoint(c1).getXCoord().toBigInteger();
            BigInteger y = X9_EC_PARAMETERS.getCurve().decodePoint(c1).getYCoord().toBigInteger();
    
            // 长度为 new SM3Digest().getDigestSize()
            final int c3Len = 32;
            byte[] c3 = new byte[c3Len];
    
            final int c2Len = plainCipher.length - c1Len - c3Len;
            byte[] c2 = new byte[c2Len];
    
            ASN1EncodableVector v = new ASN1EncodableVector();
            v.add(new ASN1Integer(x));
            v.add(new ASN1Integer(y));
    
            if (mode == SM2Engine.Mode.C1C3C2) {
                System.arraycopy(plainCipher, c1.length, c3, 0, c3Len);
                System.arraycopy(plainCipher, c1Len + c3Len, c2, 0, c2Len);
                v.add(new DEROctetString(c3));
                v.add(new DEROctetString(c2));
            } else {
                System.arraycopy(plainCipher, plainCipher.length - c3Len, c3, 0, c3Len);
                System.arraycopy(plainCipher, c1Len, c2, 0, c2Len);
                v.add(new DEROctetString(c2));
                v.add(new DEROctetString(c3));
            }
            try {
                return new DERSequence(v).getEncoded(ASN1Encoding.DER);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    
    
    
    }
    
    

    # GB35114 SM2签名

    查看代码
    
    @Slf4j
    public class GB35114SignUtil {
    
    
        /**
         * 进行 sign1签名
         * sign(random2+random1+ serverid)
         * @param r2 FDWSF生成随机数
         * @param r1 SIP服务器随机数
         * @param serverId SIP服务器ID
         * @return 签名数据
         */
        public static String genSign1(String r2, String r1, String serverId) {
            return Sm2Util.sign( sign1Format(r2, r1, serverId));
        }
    
    
        /**
         *  sign 数据组装
         * (random2+random1+ serverId)
         * @param r2 FDWSF生成随机数
         * @param r1 SIP服务器随机数
         * @param serverId SIP服务器ID
         */
        private static String sign1Format(String r2, String r1, String serverId) {
            return String.format("%s%s%s", r2, r1, serverId);
        }
    
    
        /**
         *  验证签名
         * @param r1 SIP服务器随机数
         * @param r2 FDWSF生成随机数
         * @param serverId SIP服务器ID
         * @param sign1 sign1
         * @param request SIP Request
         * @param error 失败处理
         */
        public static void vifSign(String r1, String r2, String serverId, String sign1,
                                   SIPRequest request,
                                   Consumer<SIPRequest> error
        ) {
            if (Sm2Util.verify(sign1Format(r2,r1, serverId),sign1)) {
                return;
            }
            error.accept(request);
            log.error("验签失败");
            throw new RuntimeException("验签失败");
        }
    
    
    
        /**
         * 进行 sign2签名
         * sign(random1+random2+deviceid+cryptkey)
         * @param r1 SIP服务器随机数
         * @param r2 FDWSF生成随机数
         * @param deviceId SIP服务器ID
         * @param cryptkey base64(VKEK公钥加密)
         * @return 签名数据
         */
        public static String genSign2(String r1, String r2, String deviceId, String cryptkey) {
            String format = sign2Format(r1, r2, deviceId, cryptkey);
            log.info("预签名数据:{}", format);
            //sign(random1+random2+deviceid+cryptkey)
            return Sm2Util.sign(format);
        }
    
    
        /**
         *  sign2 数据组装
         * (random2+random1+ serverid)
         * @param r1 SIP服务器随机数
         * @param r2 FDWSF生成随机数
         * @param deviceId 设备ID
         * @param cryptkey cryptkey
         */
        private static String sign2Format(String r1, String r2, String deviceId, String cryptkey) {
            return String.format("%s%s%s%s", r1, r2, deviceId, cryptkey);
        }
    
    
        /**
         * 进行 sign2验证
         * (random2+random1+ serverid)
         * @param r1 SIP服务器随机数
         * @param r2 FDWSF生成随机数
         * @param deviceId 设备ID
         * @param cryptkey cryptkey
         * @param sign2 sign2
         * @param request SIP Request
         * @param error 失败处理
         */
        public static void vifSig2(String r1, String r2, String deviceId, String cryptkey,String sign2,
                                   SIPMessage request,
                                   Consumer<SIPMessage> error
    
        ) {
            if (Sm2Util.verify(sign2Format(r1, r2, deviceId,cryptkey),sign2)) {
                return;
            }
            error.accept(request);
            log.error("验签失败");
            throw new RuntimeException("验签失败");
        }
    
    }
    
    
    
    上次更新: 2025/05/14, 01:34:05
    GB35114
    SM3工具类

    ← GB35114 SM3工具类→

    最近更新
    01
    Caddy操作指南
    04-25
    02
    Swap空间
    04-22
    03
    Alist使用
    04-21
    更多文章>
    Theme by Vdoing | Copyright © 2022-2025 YAN | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式