精华内容
下载资源
问答
  • sm2加密
    千次阅读
    2021-11-29 11:59:40

    一、依赖包

            <!-- hutool的 SM2 加密-->
            <dependency>
                <groupId>org.bouncycastle</groupId>
                <artifactId>bcprov-jdk15to18</artifactId>
                <version>1.68</version>
            </dependency>
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>5.7.2</version>
            </dependency>

    二、工具类

    首先创建一个用于存储加密解密内容的实体:

    package com.bw.note.util.SM2.SP;
    
    import lombok.Data;
    import lombok.EqualsAndHashCode;
    
    import java.io.Serializable;
    
    @Data
    @EqualsAndHashCode(callSuper = false)
    public class ApiEncryptInfoDTO implements Serializable {
    
        private static final long serialVersionUID = 255205006827117733L;
    
        /**
         * 加密类型(2:sm2加密,4:sm4加密)
         */
        private String type;
    
        /**
         * 非对称加密私钥
         */
        private String privateKey;
    
        /**
         * 非对称加密公钥
         */
        private String publicKey;
    
        /**
         * 对称加密密钥
         */
        private String key;
    
        /**
         * 原始数据
         */
        private String data;
    
        /**
         * 加密后数据
         */
        private String dataHex;
    
        /**
         * 非对称加密签名
         */
        private String sign;
    }
    

     接着是具体的加密解密过程工具类:

    package com.bw.note.util.SM2.SP;
    
    import cn.hutool.core.util.CharsetUtil;
    import cn.hutool.core.util.HexUtil;
    import cn.hutool.core.util.RandomUtil;
    import cn.hutool.core.util.StrUtil;
    import cn.hutool.crypto.BCUtil;
    import cn.hutool.crypto.SmUtil;
    import cn.hutool.crypto.asymmetric.KeyType;
    import cn.hutool.crypto.asymmetric.SM2;
    import cn.hutool.crypto.symmetric.SymmetricCrypto;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang.StringUtils;
    import org.bouncycastle.crypto.engines.SM2Engine;
    import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
    import org.bouncycastle.crypto.params.ECPublicKeyParameters;
    import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
    
    @Slf4j
    public class SM2Utils {
    
        /**
         * SM2加密
         *
         * @param dto 包含加解密相关参数信息的实体
         * @return 处理结果
         */
        public static ApiEncryptInfoDTO encrypt2Data(ApiEncryptInfoDTO dto){
            String publicKey = dto.getPublicKey();
            // 若为空,使用默认
            if (StringUtils.isBlank(publicKey)) {
                publicKey = "04db9629dd33ba568e9507add5df6587a0998361a03d3321948b448c653c2c1b7056434884ab6f3d1c529501f166a336e86f045cea10dffe58aa82ea13d7253763";
            }
            String data = dto.getData();
            //创建sm2 对象
            SM2 sm2 = getSM2(null, publicKey);
            String dataHex = sm2.encryptBcd(data, KeyType.PublicKey);
            dto.setDataHex(dataHex);
            return dto;
        }
    
        /**
         * SM2解密
         * @param dto 包含加解密相关参数信息的实体
         * @return 处理结果
         */
        public static ApiEncryptInfoDTO decrypt2Data(ApiEncryptInfoDTO dto){
            String privateKey = dto.getPrivateKey();
            // 若为空,使用默认
            if (StringUtils.isBlank(privateKey)) {
                privateKey = "1ebf8b341c695ee456fd1a41b82645724bc25d79935437d30e7e4b0a554baa5e";
            }
            String dataHex = dto.getDataHex();
            try {
                //创建sm2 对象
                SM2 sm2 = getSM2(privateKey, null);
                String data = StrUtil.utf8Str(sm2.decryptFromBcd(dataHex, KeyType.PrivateKey));
                dto.setData(data);
            } catch (Exception e) {
                log.error("SM2解密失败", e);
            }
            return dto;
        }
    
        /**
         * SM4加密
         *
         * @param dto 包含加解密相关参数信息的实体
         * @return 处理结果
         */
        public static ApiEncryptInfoDTO encrypt4Data(ApiEncryptInfoDTO dto) {
            //指定的密钥
            String key = dto.getKey();
            // 若为空,使用默认
            if (StringUtils.isBlank(key)) {
                key = "zps9yv341b3s90c2";
            }
            String data = dto.getData();
            try {
                SymmetricCrypto sm4 = SmUtil.sm4(key.getBytes(CharsetUtil.CHARSET_UTF_8));
                String dataHex = sm4.encryptHex(data);
                dto.setDataHex(dataHex);
            } catch (Exception e) {
                log.error("加密数据异常,异常数据:" + data, e);
            }
            return dto;
        }
    
        /**
         * SM4解密
         *
         * @param dto 包含加解密相关参数信息的实体
         * @return 处理结果
         */
        public static ApiEncryptInfoDTO decrypt4Data(ApiEncryptInfoDTO dto) {
            //指定的密钥
            String key = dto.getKey();
            // 若为空,使用默认
            if (StringUtils.isBlank(key)) {
                key = "zps9yv341b3s90c2";
            }
            String dataHex = dto.getDataHex();
            try {
                SymmetricCrypto sm4 = SmUtil.sm4(key.getBytes(CharsetUtil.CHARSET_UTF_8));
                String data = sm4.decryptStr(dataHex);
                dto.setData(data);
            } catch (Exception e) {
                log.error("解密数据异常,异常数据:" + dataHex, e);
            }
            return dto;
        }
    
        /**
         * 获取SM2加密工具对象
         *
         * @param privateKey 加密私钥
         * @param publicKey  加密公钥
         * @return 处理结果
         */
        private static SM2 getSM2(String privateKey, String publicKey) {
            ECPrivateKeyParameters ecPrivateKeyParameters = null;
            ECPublicKeyParameters ecPublicKeyParameters = null;
            if (StringUtils.isNotBlank(privateKey)) {
                ecPrivateKeyParameters = BCUtil.toSm2Params(privateKey);
            }
            if (StringUtils.isNotBlank(publicKey)) {
                if (publicKey.length() == 130) {
                    //这里需要去掉开始第一个字节 第一个字节表示标记
                    publicKey = publicKey.substring(2);
                }
                String xhex = publicKey.substring(0, 64);
                String yhex = publicKey.substring(64, 128);
                ecPublicKeyParameters = BCUtil.toSm2Params(xhex, yhex);
            }
            //创建sm2 对象
            SM2 sm2 = new SM2(ecPrivateKeyParameters, ecPublicKeyParameters);
            sm2.usePlainEncoding();
            sm2.setMode(SM2Engine.Mode.C1C2C3);
            return sm2;
        }
    
        /**
         * 生成一对 C1C2C3 格式的SM2密钥
         *
         * @return 处理结果
         */
        public static ApiEncryptInfoDTO getSM2Key() {
            ApiEncryptInfoDTO dto = new ApiEncryptInfoDTO();
            //创建sm2 对象
            SM2 sm2 = SmUtil.sm2();
            byte[] privateKeyByte = BCUtil.encodeECPrivateKey(sm2.getPrivateKey());
            //这里公钥不压缩  公钥的第一个字节用于表示是否压缩  可以不要
            byte[] publicKeyByte = ((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false);
            try {
                String privateKey = HexUtil.encodeHexStr(privateKeyByte);
                String publicKey = HexUtil.encodeHexStr(publicKeyByte);
                dto.setPublicKey(publicKey);
                dto.setPrivateKey(privateKey);
            } catch (Exception e) {
                log.error("获取SM2密钥出错", e);
            }
            return dto;
        }
    
        /**
         * 获取一个随机的SM4密钥
         *
         * @return 处理结果
         */
        public static ApiEncryptInfoDTO getSM4Key() {
            String sm4Key = RandomUtil.randomString(RandomUtil.BASE_CHAR_NUMBER, 16);
            ApiEncryptInfoDTO dto = new ApiEncryptInfoDTO();
            dto.setKey(sm4Key);
            return dto;
        }
    }
    

    最后是测试工具类

    package com.bw.note.util.SM2.SP;
    
    import org.junit.Test;
    
    public class test {
    
        /**
         * 测试SM2加密
         */
        @Test
        public void test01(){
            ApiEncryptInfoDTO dto = new ApiEncryptInfoDTO();
            dto.setData("123456");
            dto = SM2Utils.encrypt2Data(dto);
            System.out.println(dto.getDataHex());
        }
    
        /**
         * 测试SM2解密
         */
        @Test
        public void test02(){
            ApiEncryptInfoDTO dto = new ApiEncryptInfoDTO();
            dto.setDataHex("046A331A8227AD1CCC7E33ECEAEF7CF1CD7D3F3EEE2218E4A0AD1BE08ED5E65F0DB6811656FAE4CD1A16D8E79DE66FCF80A08158CD7E34523E76975789B18AE2C9FF9012BD47E0F84BC778538D6A6C17304A83F2F57014EC0C257987D8DA93403D53F193234DB8");
            dto = SM2Utils.decrypt2Data(dto);
            System.out.println(dto.getData());
        }
    
        /**
         * 生成一对 C1C2C3 格式的SM2密钥
         */
        @Test
        public void test03(){
            ApiEncryptInfoDTO dto = SM2Utils.getSM2Key();
            System.out.println(dto.getPublicKey());
            System.out.println(dto.getPrivateKey());
        }
    
        /**
         * 获取一个随机的SM4密钥
         */
        @Test
        public void test04(){
            ApiEncryptInfoDTO dto = SM2Utils.getSM4Key();
            System.out.println(dto.getKey());
        }
    
        /**
         * 测试SM4加密
         */
        @Test
        public void test05(){
            ApiEncryptInfoDTO dto = new ApiEncryptInfoDTO();
            dto.setData("123456");
            dto = SM2Utils.encrypt4Data(dto);
            System.out.println(dto.getDataHex());
        }
    
        /**
         * 测试SM4解密
         */
        @Test
        public void test06(){
            ApiEncryptInfoDTO dto = new ApiEncryptInfoDTO();
            dto.setDataHex("0c878839ddba1631931ca9e7f9c981eb");
            dto = SM2Utils.decrypt4Data(dto);
            System.out.println(dto.getData());
        }
    }
    

    更多相关内容
  • Java 算法SM2加密解密

    千次阅读 2021-09-27 16:31:52
    什么是SM2 SM2是国家密码管理局于2010年12月17日发布的椭圆曲线公钥密码算法。 SM2 算法和 RSA 算法都是公钥密码算法,SM2 算法是一种更先进安全的算法,在我们国家商用密码体系中被用来替换 RSA 算法。 随着密码...

    简介

    什么是SM2

    SM2是国家密码管理局于2010年12月17日发布的椭圆曲线公钥密码算法。

    SM2 算法和 RSA 算法都是公钥密码算法,SM2 算法是一种更先进安全的算法,在我们国家商用密码体系中被用来替换 RSA 算法。

    随着密码技术和计算机技术的发展,目前常用的 1024RSA 算法面临严重的安全威胁,我们国家密码管理部门经过研究,决定采用 SM2 椭圆曲线算法替换RSA算法。

    SM2算法和RSA算法比较

    SM2性能更优更安全:密码复杂度高、处理速度快、机器性能消耗更小

    -SM2RSA
    算法结构基本椭圆曲线(ECC)基于特殊的可逆模幂运算
    计算复杂度完全指数级亚指数级
    存储空间192-256bit2048-4096bit
    秘钥生成速度较RSA算法快百倍以上
    解密加密速度较快一般

    POM依赖

    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-ext-jdk15to18</artifactId>
        <version>1.68</version>
    </dependency>
    <dependency>
    	<groupId>org.bouncycastle</groupId>
    	<artifactId>bcprov-jdk15to18</artifactId>
    	<version>1.68</version>
    </dependency>
    

    Java工具类

    package com.file.system.tools.sm2;
    
    import org.bouncycastle.asn1.gm.GMNamedCurves;
    import org.bouncycastle.asn1.x9.X9ECParameters;
    import org.bouncycastle.crypto.engines.SM2Engine;
    import org.bouncycastle.crypto.params.ECDomainParameters;
    import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
    import org.bouncycastle.crypto.params.ECPublicKeyParameters;
    import org.bouncycastle.crypto.params.ParametersWithRandom;
    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.jce.spec.ECParameterSpec;
    import org.bouncycastle.jce.spec.ECPrivateKeySpec;
    import org.bouncycastle.jce.spec.ECPublicKeySpec;
    import org.bouncycastle.util.encoders.Hex;
    
    import java.math.BigInteger;
    import java.security.*;
    import java.security.spec.ECGenParameterSpec;
    
    /**
     * @ClassName SM2Utils
     * @Description SM2算法工具类
     * @Author msx
     * @Date 2021/9/24 16:50
     * @Version 1.0
     */
    public class SM2Utils {
    
        /**
         * @Description 生成秘钥对
         * @Author msx
         * @return KeyPair
         */
        public static KeyPair createECKeyPair() {
            //使用标准名称创建EC参数生成的参数规范
            final ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");
    
            // 获取一个椭圆曲线类型的密钥对生成器
            final KeyPairGenerator kpg;
            try {
                kpg = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
                // 使用SM2算法域参数集初始化密钥生成器(默认使用以最高优先级安装的提供者的 SecureRandom 的实现作为随机源)
                // kpg.initialize(sm2Spec);
    
                // 使用SM2的算法域参数集和指定的随机源初始化密钥生成器
                kpg.initialize(sm2Spec, new SecureRandom());
    
                // 通过密钥生成器生成密钥对
                return kpg.generateKeyPair();
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    
        /**
         * @Description 公钥加密
         * @Author msx
         * @param publicKeyHex SM2十六进制公钥
         * @param data         明文数据
         * @return String
         */
        public static String encrypt(String publicKeyHex, String data) {
            return encrypt(getECPublicKeyByPublicKeyHex(publicKeyHex), data, 1);
        }
    
        /**
         * @Description 公钥加密
         * @Author msx
         * @param publicKey SM2公钥
         * @param data      明文数据
         * @param modeType  加密模式
         * @return String
         */
        public static String encrypt(BCECPublicKey publicKey, String data, int modeType) {
            //加密模式
            SM2Engine.Mode mode = SM2Engine.Mode.C1C3C2;
            if (modeType != 1) {
                mode = SM2Engine.Mode.C1C2C3;
            }
            //通过公钥对象获取公钥的基本域参数。
            ECParameterSpec ecParameterSpec = publicKey.getParameters();
            ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(),
                    ecParameterSpec.getG(), ecParameterSpec.getN());
            //通过公钥值和公钥基本参数创建公钥参数对象
            ECPublicKeyParameters ecPublicKeyParameters = new ECPublicKeyParameters(publicKey.getQ(), ecDomainParameters);
            //根据加密模式实例化SM2公钥加密引擎
            SM2Engine sm2Engine = new SM2Engine(mode);
            //初始化加密引擎
            sm2Engine.init(true, new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom()));
            byte[] arrayOfBytes = null;
            try {
                //将明文字符串转换为指定编码的字节串
                byte[] in = data.getBytes("utf-8");
                //通过加密引擎对字节数串行加密
                arrayOfBytes = sm2Engine.processBlock(in, 0, in.length);
            } catch (Exception e) {
                System.out.println("SM2加密时出现异常:" + e.getMessage());
                e.printStackTrace();
            }
            //将加密后的字节串转换为十六进制字符串
            return Hex.toHexString(arrayOfBytes);
        }
    
        /**
         * @Description 私钥解密
         * @Author msx
         * @param privateKeyHex SM2十六进制私钥
         * @param cipherData    密文数据
         * @return String
         */
        public static String decrypt(String privateKeyHex, String cipherData) {
            return decrypt(getBCECPrivateKeyByPrivateKeyHex(privateKeyHex), cipherData, 1);
        }
    
        /**
         * @Description 私钥解密
         * @Author msx
         * @param privateKey SM私钥
         * @param cipherData 密文数据
         * @param modeType   解密模式
         * @return
         */
        public static String decrypt(BCECPrivateKey privateKey, String cipherData, int modeType) {
            //解密模式
            SM2Engine.Mode mode = SM2Engine.Mode.C1C3C2;
            if (modeType != 1)
                mode = SM2Engine.Mode.C1C2C3;
            //将十六进制字符串密文转换为字节数组(需要与加密一致,加密是:加密后的字节数组转换为了十六进制字符串)
            byte[] cipherDataByte = Hex.decode(cipherData);
            //通过私钥对象获取私钥的基本域参数。
            ECParameterSpec ecParameterSpec = privateKey.getParameters();
            ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(),
                    ecParameterSpec.getG(), ecParameterSpec.getN());
            //通过私钥值和私钥钥基本参数创建私钥参数对象
            ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(privateKey.getD(),
                    ecDomainParameters);
            //通过解密模式创建解密引擎并初始化
            SM2Engine sm2Engine = new SM2Engine(mode);
            sm2Engine.init(false, ecPrivateKeyParameters);
            String result = null;
            try {
                //通过解密引擎对密文字节串进行解密
                byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
                //将解密后的字节串转换为utf8字符编码的字符串(需要与明文加密时字符串转换成字节串所指定的字符编码保持一致)
                result = new String(arrayOfBytes, "utf-8");
            } catch (Exception e) {
                System.out.println("SM2解密时出现异常" + e.getMessage());
            }
            return result;
        }
        //椭圆曲线ECParameters ASN.1 结构
        private static X9ECParameters x9ECParameters = GMNamedCurves.getByName("sm2p256v1");
        //椭圆曲线公钥或私钥的基本域参数。
        private static ECParameterSpec ecDomainParameters = new ECParameterSpec(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN());
    
        /**
         * @Description 公钥字符串转换为 BCECPublicKey 公钥对象
         * @Author msx
         * @param pubKeyHex 64字节十六进制公钥字符串(如果公钥字符串为65字节首个字节为0x04:表示该公钥为非压缩格式,操作时需要删除)
         * @return BCECPublicKey SM2公钥对象
         */
        public static BCECPublicKey getECPublicKeyByPublicKeyHex(String pubKeyHex) {
            //截取64字节有效的SM2公钥(如果公钥首个字节为0x04)
            if (pubKeyHex.length() > 128) {
                pubKeyHex = pubKeyHex.substring(pubKeyHex.length() - 128);
            }
            //将公钥拆分为x,y分量(各32字节)
            String stringX = pubKeyHex.substring(0, 64);
            String stringY = pubKeyHex.substring(stringX.length());
            //将公钥x、y分量转换为BigInteger类型
            BigInteger x = new BigInteger(stringX, 16);
            BigInteger y = new BigInteger(stringY, 16);
            //通过公钥x、y分量创建椭圆曲线公钥规范
            ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(x9ECParameters.getCurve().createPoint(x, y), ecDomainParameters);
            //通过椭圆曲线公钥规范,创建出椭圆曲线公钥对象(可用于SM2加密及验签)
            return new BCECPublicKey("EC", ecPublicKeySpec, BouncyCastleProvider.CONFIGURATION);
        }
    
        /**
         * @Description 私钥字符串转换为 BCECPrivateKey 私钥对象
         * @Author msx
         * @param privateKeyHex 32字节十六进制私钥字符串
         * @return BCECPrivateKey SM2私钥对象
         */
        public static BCECPrivateKey getBCECPrivateKeyByPrivateKeyHex(String privateKeyHex) {
            //将十六进制私钥字符串转换为BigInteger对象
            BigInteger d = new BigInteger(privateKeyHex, 16);
            //通过私钥和私钥域参数集创建椭圆曲线私钥规范
            ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(d, ecDomainParameters);
            //通过椭圆曲线私钥规范,创建出椭圆曲线私钥对象(可用于SM2解密和签名)
            return new BCECPrivateKey("EC", ecPrivateKeySpec, BouncyCastleProvider.CONFIGURATION);
        }
    
        public static void main(String[] args) {
            String publicKeyHex = null;
            String privateKeyHex = null;
            KeyPair keyPair = createECKeyPair();
            PublicKey publicKey = keyPair.getPublic();
            if (publicKey instanceof BCECPublicKey) {
                //获取65字节非压缩缩的十六进制公钥串(0x04)
                publicKeyHex = Hex.toHexString(((BCECPublicKey) publicKey).getQ().getEncoded(false));
                System.out.println("---->SM2公钥:" + publicKeyHex);
            }
            PrivateKey privateKey = keyPair.getPrivate();
            if (privateKey instanceof BCECPrivateKey) {
                //获取32字节十六进制私钥串
                privateKeyHex = ((BCECPrivateKey) privateKey).getD().toString(16);
                System.out.println("---->SM2私钥:" + privateKeyHex);
            }
    
            /**
             * 公钥加密
             */
            String data = "=========待加密数据=========";
    
            //将十六进制公钥串转换为 BCECPublicKey 公钥对象
            String encryptData = encrypt(publicKeyHex, data);
            System.out.println("---->加密结果:" + encryptData);
    
            /**
             * 私钥解密
             */
            //将十六进制私钥串转换为 BCECPrivateKey 私钥对象
            data = decrypt(privateKeyHex, encryptData);
            System.out.println("---->解密结果:" + data);
        }
    }
    
    
    扩展资料

    国密即国家密码局认定的国产密码算法。主要有SM1,SM2,SM3,SM4。密钥长度和分组长度均为128位。
    (1)SM1 为对称加密。其加密强度与AES相当。该算法不公开,调用该算法时,需要通过加密芯片的接口进行调用。
    (2)SM2为非对称加密,基于ECC。该算法已公开。由于该算法基于ECC,故其签名速度与秘钥生成速度都快于RSA。ECC 256位(SM2采用的就是ECC 256位的一种)安全强度比RSA 2048位高,但运算速度快于RSA。
    (3)SM3 消息摘要。可以用MD5作为对比理解。该算法已公开。校验结果为256位。
    (4)SM4 无线局域网标准的分组数据算法。对称加密,密钥长度和分组长度均为128位。

    这里有一篇关于SM1、SM2 、SM3、 SM4算法详解

    展开全文
  • 基于 gmssl实现的sm2加密(C++)

    千次阅读 2022-04-16 11:46:42
    项目中需要用到sm2加密,在网上搜索了一下相关的库,发现只有openssl和gmssl这两个库可以用,于是基于gmssl库做了封装,gmssl的版本是:GmSSL 2.5.4 - OpenSSL 1.1.0d 19 Jun 2019 搞这个库的确要费不少功夫,现在...

    项目中需要用到sm2加密,在网上搜索了一下相关的库,发现只有openssl和gmssl这两个库可以用,于是基于gmssl库做了封装,gmssl的版本是:GmSSL 2.5.4 - OpenSSL 1.1.0d  19 Jun 2019

    搞这个库的确要费不少功夫,现在分享出来给需要的人。目前我是用在linux环境中,因此编译成linux动态库,并且屏蔽相关库的头文件和符号,只暴露sm2加解密相关的接口符号,gmssl库通过静态库的方式引用。

    关于sm2加密有几个比较重要的参数,第一个是椭圆曲线参数,第二个是密文编码方式,第三个是哈希算法,目前我们用的都是固定的参数,所以封装的时候没有提供参数选择这些功能,需要的可以自行扩展。下面的sm2加密相关从参数为:使用默认的椭圆曲线参数(sm2p256v1),ASN.1/DER编码方式(C1|C3|C2编码方式) ,哈希(杂凑)算法使用sm3

    gmutil.h头文件:

    #ifndef __GM_UTIL_H__
    #define __GM_UTIL_H__
    #include <string>
    using namespace std;
    
    #ifdef _WIN32
    #define UNIX_EXPORT
    #else
    #define UNIX_EXPORT __attribute__((visibility("default")))
    #endif
    // namespace GM
    //{
    
    // 错误码
    enum EGMErrorCode
    {
        GM_UTIL_CODE_OK = 0,
        GM_UTIL_CODE_CREATE_EV_KEY_FAILED, // 密钥解析失败
        GM_UTIL_CODE_SM2_ENCRYPT_FAILED,   // SM2加密失败
        GM_UTIL_CODE_SM2_DECRYPT_FAILED,   // SM2解密失败
        GM_UTIL_CODE_NOT_SM2P256V1,        // 不是默认的sm2p256v1椭圆曲线参数
        GM_UTIL_CODE_INIT_BIO_FAILED,      // 初始化BIO失败
        GM_UTIL_CODE_CIPHER_TEXT_TO_BIO_FAILED,      // 加密数据存储到BIO失败
        GM_UTIL_CODE_BIO_DATA_TO_MEM_FAILED,      // BIO数据转存到缓冲区失败
        GM_UTIL_CODE_BIO_DATA_TO_CIPHER_TEXT_FAILED,      // BIO数据转成Ciphertext结构失败
    };
    extern "C"
    {
        // 从文件中读入公钥/私钥数据到string中,失败返回空字符串
        UNIX_EXPORT string GmReadKeyFromFile(string strFileName);
    
        /**
         * @brief sm2加密,使用默认的椭圆曲线参数(NID_sm2p256v1),ASN.1/DER编码方式(C1|C3|C2编码方式) ,哈希(杂凑)算法使用sm3
         * @param strPubKey 公钥数据
         * @param strIn 需要加密的数据
         * @param strCiphertext 密文,加密后的密文不是可见字符
         * @return 返回GM_UTIL_ERR_OK表示加密成功,否则失败,具体见EGMErrorCode定义
         */
        UNIX_EXPORT int GmSm2Encrypt(string strPubKey, const string &strIn, string &strCiphertext);
    
        /**
         * @brief sm2解密,使用默认的椭圆曲线参数(NID_sm2p256v1),ASN.1/DER编码方式(C1|C3|C2编码方式),哈希(杂凑)算法使用sm3
         * @param strPubKeyFile 私钥数据
         * @param strCiphertext 需要解密的数据(不是可见字符)
         * @param strOut 解密后的明文
         * @return 返回GM_UTIL_ERR_OK表示解密成功,否则失败,具体见EGMErrorCode定义
         */
        UNIX_EXPORT int GmSm2Decrypt(string strPriKey, const string &strCiphertext, string &strOut);
    
        // 将二进制数据转换成十六进制字符串
        UNIX_EXPORT string GmByte2HexStr(const string &data, bool bLowerCase = true);
    
        // 将十六进制字符串转换成二进制
        UNIX_EXPORT string GmHexStr2Byte(const string& hex, bool bLowerCase = true);
    }
    
    // } // namespace GM
    #endif // end __GM_UTIL_H__

    gmutil.cpp文件:

    #include "gmutil.h"
    #include <iostream>
    #include<fstream>
    #include<sstream>
    #include <stdio.h>
    #include <openssl/evp.h>
    #include <openssl/pem.h>
    #include <openssl/sm2.h>
    #include <openssl/bio.h>
    //using namespace GM;
    
    /**
     * @brief 使用公钥/私钥数据获取EV_KEY对象
     * @param key 公钥/私钥数据
     * @param is_public 是否公钥
     * @return 失败返回NULL
     */
    static EC_KEY *CreateEC(unsigned char *key, int is_public)
    {
        EC_KEY *ec_key = NULL;
        BIO *keybio = NULL;
        keybio = BIO_new_mem_buf(key, -1);
     
        if (keybio == NULL) {
            printf("%s", "[BIO_new_mem_buf]->key len=%d,Failed to Get Key", strlen((char *) key));
            return NULL;
        }
     
        if (is_public) {
            ec_key = PEM_read_bio_EC_PUBKEY(keybio, NULL, NULL, NULL);
        } else {
            ec_key = PEM_read_bio_ECPrivateKey(keybio, NULL, NULL, NULL);
        }
     
        if (ec_key == NULL) {
            printf("Failed to Get Key");
            BIO_free_all(keybio);
            return NULL;
        }
    
        BIO_free_all(keybio); // 此处是不是要free?
        return ec_key;
    }
    
    int GmSm2Encrypt(string strPubKey, const string &strIn, string &strCiphertext)
    {
        EC_KEY *evKey = CreateEC((unsigned char *)strPubKey.c_str(), 1);
        if (NULL == evKey)
        {
            return GM_UTIL_CODE_CREATE_EV_KEY_FAILED;
        }
        
        // 目前只支持默认的sm2p256v1椭圆曲线参数
        if (!EC_KEY_is_sm2p256v1(evKey))
        {
            EC_KEY_free(evKey);
            return GM_UTIL_CODE_NOT_SM2P256V1;
        }
    
        // 加密后的密文会比明文长97字节
        unsigned char *buff = NULL;
        size_t outLen = 0;
        SM2CiphertextValue *cval = NULL;
        size_t mlen, clen;
        unsigned char *p;
    
        if (NULL == (cval = SM2_do_encrypt(EVP_sm3(), (const unsigned char *)strIn.c_str(), strIn.size(), evKey)))
        {
            EC_KEY_free(evKey);
            return GM_UTIL_CODE_SM2_ENCRYPT_FAILED;
        }
        
        BIO *bOut = BIO_new(BIO_s_mem());
        if (NULL == bOut)
        {
            EC_KEY_free(evKey);
            SM2CiphertextValue_free(cval);
            return GM_UTIL_CODE_INIT_BIO_FAILED;
        }
    
        if (i2d_SM2CiphertextValue_bio(bOut, cval) <= 0)
        {
            SM2CiphertextValue_free(cval);
            BIO_free(bOut);
            EC_KEY_free(evKey);
            return GM_UTIL_CODE_CIPHER_TEXT_TO_BIO_FAILED;
        }
    
        if (0 == (outLen = BIO_get_mem_data(bOut, (char **)&buff)))
        {
            SM2CiphertextValue_free(cval);
            BIO_free(bOut);
            EC_KEY_free(evKey);
            return GM_UTIL_CODE_BIO_DATA_TO_MEM_FAILED;
        }
    
        strCiphertext.assign((char *)buff, outLen);
        // 释放内存
        SM2CiphertextValue_free(cval);
        BIO_free(bOut);
        EC_KEY_free(evKey);
        // OPENSSL_free(buff); //此处释放会挂掉,不应该free,应该是在BIO_free的时候内存已经被释放掉
        return GM_UTIL_CODE_OK;
    }
    
    
    int GmSm2Decrypt(string strPriKey, const string &strCiphertext, string &strOut)
    {
        EC_KEY *evKey = CreateEC((unsigned char *)strPriKey.c_str(), 0);
        if (NULL == evKey)
        {
            return GM_UTIL_CODE_CREATE_EV_KEY_FAILED;
        }
    
        if (!EC_KEY_is_sm2p256v1(evKey))
        {
            EC_KEY_free(evKey);
            return GM_UTIL_CODE_NOT_SM2P256V1;
        }
        BIO *bIn = NULL;
        bIn = BIO_new_mem_buf(strCiphertext.c_str(), strCiphertext.size());
        if (bIn == NULL)
        {
            EC_KEY_free(evKey);
            return GM_UTIL_CODE_INIT_BIO_FAILED;
        }
    
        int ret = 0;
    	SM2CiphertextValue *cval = NULL;
    	void *buf = NULL;
    	size_t siz;
        const EVP_MD* md = EVP_sm3();
    
        if (NULL == (cval = d2i_SM2CiphertextValue_bio(bIn, NULL)))
        {
            BIO_free(bIn);
            EC_KEY_free(evKey);
            return GM_UTIL_CODE_BIO_DATA_TO_CIPHER_TEXT_FAILED;
        }
    
    	if (0 == SM2_do_decrypt(md, cval, NULL, &siz, evKey) || !(buf = OPENSSL_malloc(siz)))
        {
            BIO_free(bIn);
            SM2CiphertextValue_free(cval);
            EC_KEY_free(evKey);
    		return GM_UTIL_CODE_SM2_DECRYPT_FAILED;
    	}
    
        if (0 == SM2_do_decrypt(md, cval, (unsigned char*)buf, &siz, evKey))
        {
            BIO_free(bIn);
            SM2CiphertextValue_free(cval);
            OPENSSL_free(buf);
            EC_KEY_free(evKey);
            return GM_UTIL_CODE_SM2_DECRYPT_FAILED;
        }
        
        strOut.assign((char*)buf, siz);
        // 释放内存
        BIO_free(bIn);
        SM2CiphertextValue_free(cval);
    	OPENSSL_free(buf);
        EC_KEY_free(evKey);
        return GM_UTIL_CODE_OK;
    }
    
    static streamsize Read(istream &stream, char *buffer, streamsize count)
    {
        streamsize reads = stream.rdbuf()->sgetn(buffer, count);
        stream.rdstate();
        stream.peek();
        return reads;
    }
    
    string GmReadKeyFromFile(string strFileName)
    {
        fstream myfile;
    	myfile.open(strFileName, ifstream::in | ifstream::binary);
    	if (!myfile.is_open())
        {
            return "";
        }
    
        char buff[1024];
        std::ostringstream oss;
        int len;
        while (!myfile.eof())
        {
            size_t read = Read(myfile, buff, sizeof(buff));
            oss << string(buff, read);
        }
    
        myfile.close();
        return oss.str();
    }
    
    static char sDigit1[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
    static char sDigit2[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    string GmByte2HexStr(const string& data, bool bLowerCase)
    {
        char *sDigit = sDigit1;
        if (!bLowerCase)
        {
            sDigit = sDigit2;
        }
        const char* pData = data.c_str();
        char cTemp;
        string strHex;
        for (unsigned int i = 0; i < data.size(); i++)
        {
            cTemp = *pData;
            pData++;
            strHex += sDigit[(cTemp >> 4) & 0x0F];
            strHex += sDigit[cTemp & 0x0F];
        }
    
        return strHex;
    }
    
    string GmHexStr2Byte(const string& hex, bool bLowerCase)
    {
        if (hex.size() % 2 != 0)
        {
            // 十六进制字符串必须是偶数长度
            return "";
        }
    
        char chA = 'a';
        if (!bLowerCase)
        {
            chA = 'A';
        }
    
        std::ostringstream oss;
        for (int i = 0; i < hex.size(); i += 2)
        {
            unsigned int highBit;
            if (hex[i] >= '0' && hex[i] <= '9')
            {
                highBit = hex[i] - '0';
            }
            else
            {
                highBit = hex[i] - chA + 10;
            }
            unsigned int lowBit;
            if (hex[i + 1] >= '0' && hex[i + 1] <= '9')
            {
                lowBit = hex[i + 1] - '0';
            }
            else
            {
                lowBit = hex[i + 1] - chA + 10;
            }
            unsigned char ch = (highBit << 4) + lowBit; 
            oss << ch;
        }
    
        return oss.str();
    }

    下面是测试验证test.cpp:

    #include "gmutil.h"
    #include <iostream>
    #include <sstream>
    
    int main(int argc, char** argv)
    {
        string strPriKey = GmReadKeyFromFile("sm2_server_private_key.key");
        string strPubKey = GmReadKeyFromFile("sm2_server_public_key.key");
        string strText = "hello world, this is a test";
        string strCipher;
        string strOut;
        std::cout << "plaintext:" << strText << std::endl;
        int nRet = GmSm2Encrypt(strPubKey, strText, strCipher);
        if (GM_UTIL_CODE_OK != nRet)
        {
            cout << "GmSm2Encrypt fail" << endl;
        }
        string strCipherTextHex = GmByte2HexStr(strCipher);
        cout << "hex ciper text:" << strCipherTextHex << endl;
        string strCipher1 = GmHexStr2Byte(strCipherTextHex);
        if (strCipher1 == strCipher)
        {
            cout << "conver hex str to byte sucess" << endl;
        }
        nRet = GmSm2Decrypt(strPriKey, strCipher1, strOut);
        std::cout << "after decrypt:" << strOut << std::endl;
    
        return 0;
    }

    编译的时候要加这几个关键的编译参数:-fvisibility=hidden -Wl,-Bsymbolic -Wl,--exclude-libs,ALL

    用来屏蔽动态库中的符号的。

    gmssl库相关函数的文档可以参考官网:国密SM2椭圆曲线密码标准 (gmssl.org)

    还有可以直接参考gmssl源码中的sm2test.c以及sm2utl.c,里面有相关的代码

    还有gmssl库用到openssl库的很多函数比如BIO等,可以参数openssl官网来使用

    参考文章:

    (20条消息) 基于GMSSL的SM2加解密测试_viqjeee的博客-CSDN博客_gmssl sm2

    (20条消息) C语言SM2算法实现(基于GMSSL)_张志翔 ̮的博客-CSDN博客_sm2实现 --这个最详细,直接有完整代码

    (25条消息) SM2算法全套(基于GMSSL)_wincent1的博客-CSDN博客_gmssl sm2算法

    展开全文
  • sm2加密源码

    2017-11-28 15:17:38
    国密SM2源码,c/c++代码,能直接编绎,可用于电力及银行等相关领域。
  • C#国密SM2加密算法实现

    千次阅读 2022-04-21 13:21:41
    最近在做数据上报,上报数据需要使用国密SM2加密算法加密后上传,以前没接触过过这个东东,所以做个简单记录,平台提供给加密的公钥,让后我们根据公钥将数据加密后,提交给接口,以保证数据安全传输。 实现代码 ...

    最近在做数据上报,上报数据需要使用国密SM2加密算法加密后上传,以前没接触过过这个东东,所以做个简单记录,平台提供给加密的公钥,让后我们根据公钥将数据加密后,提交给接口,以保证数据安全传输。

    实现代码

    using Org.BouncyCastle.Crypto.Engines;
    using Org.BouncyCastle.Crypto.Parameters;
    using Org.BouncyCastle.Security;
    using Org.BouncyCastle.Utilities.Encoders;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace HSSB
    {
        /******************************************************** 
          * 项目名称: Program.cs
          * 命名空间 : HSSB
          * 类 名 称 : Program
          * 作   者  : RoyeeCai
          * 邮   箱  : caimh0223@163.com
          * 概   述  : 
          * 创建时间 : 2022-04-20 12:23:40
          * 更新时间 : 2022-04-20 12:23:40
          * CLR版本  : 4.0.30319.42000
          * ******************************************************
          * Copyright@RoyeeCai 2022 .All rights reserved.
          * ******************************************************
          */
        class Program
        {
            static void Main(string[] args)
            {
                // 公钥  平台提供
                String publicKey = "3059301306072a8648ce3d020106082a811ccf5501822d03420004aaa1dae5c13eacf0bf98a3570070101f1e0ce7be2bc000a702595a136ac18e0c109119314897b51d81e29a746d0913a7f364b5853dfcb901eff6826401981791";
                //待加密字符串
                String val = "{\"userName\":\"王小宝\",\"age\":\"10\"}";
    
                //String s1 = Util4Hex.bytesToHexString(EncryptPublic(publicKey, Encoding.Default.GetBytes(val)));
                String s = Encoding.UTF8.GetString(Hex.Encode(EncryptPublic(publicKey, Encoding.UTF8.GetBytes(val))));
                //Console.WriteLine(s1);
                Console.WriteLine("=========以下为加密后的字符串=========");
                Console.WriteLine(s);  
                Console.ReadKey();
            }
    
            /// <summary>
            /// 生成SM2加密字符串
            /// </summary>
            /// <param name="pubKey"></param>
            /// <param name="srcData"></param>
            /// <returns></returns>
            public static byte[] EncryptPublic(String pubKey, byte[] srcData)
            {
                //byte[] publicKeyByte = Util4Hex.hexStringToBytes(pubKey);
                byte[] publicKeyByte = hexStringToBytes(pubKey);
                ECPublicKeyParameters ECPPublicKey = (ECPublicKeyParameters)PublicKeyFactory.CreateKey(publicKeyByte);
                SM2Engine engine = new SM2Engine();
                ParametersWithRandom pwr = new ParametersWithRandom(ECPPublicKey, new SecureRandom());
                engine.Init(true, pwr);
                return engine.ProcessBlock(srcData, 0, srcData.Length);
            }
    
            /**
             * Convert hex string to byte[]
             * 
             * @param hexString the hex string
             * @return byte[]
             */
            public static byte[] hexStringToBytes(String hexString)
            {
                if (hexString == null || hexString.Equals(""))
                {
                    return null;
                }
                hexString = hexString.ToUpper();
                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;
            }
    
            /**
             * Convert char to byte
             * 
             * @param c char
             * @return byte
             */
            private static byte charToByte(char c)
            {
                return (byte)"0123456789ABCDEF".IndexOf(c);
            }
        }
    }
    
    

    运行效果

    在这里插入图片描述

    展开全文
  • SM2加密

    万次阅读 2019-05-06 10:48:57
    1、引入依赖 <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.54</version> </dependency>......
  • 前端md5,aes,sm2加密的使用

    千次阅读 2022-05-25 16:41:21
    也对应着前端常使用的三种方法md5,aes和sm2。 散列算法是不可逆的,安全姓极高但灵活性不够。常用于对身份信息的验证,例如登录。 对称算法前后端使用同一个密钥,加密速度快,但安全性低于非对称算法。可使用于对...
  • vue/java使用国密SM2加密

    千次阅读 2022-03-08 14:02:44
    本文前后端均使用国密SM2加密,后端在gateway中统一拦截,解密和加密。 流程步骤为: 1、前端对请求数据进行加密; 2、网关请求拦截器拦截前端请求,并对请求数据解密; 3、网关响应拦截器拦截后端响应数据,并对...
  • vue前端 sm2加密

    千次阅读 2021-08-20 14:23:18
    vue使用sm2加密首先必须安装下载依赖:npm install --save sm-crypto 下载报错的话可以用淘宝镜像下载:npm install chromedriver --chromedriver_cdnurl=http://cdn.npm.taobao.org/dist/chromedriver sm2在vue中...
  • 国密sm2加密算法 前后端加密实现

    千次阅读 2022-07-07 15:13:05
    国密sm2加密算法,前后端实现
  • 近期由于公司项目的需要开始研究国密SM2加密.网上也找了许久没有,可是没有关于iOS方面的实现,有很多基于openssl的C语言的实现,但是因为是C的小白,而且代码较乱,也没注释,被坑了不少的下载积分.后来找到GmSSL有实现...
  • Python版SM2加密

    千次阅读 2021-09-17 10:36:59
    在使用Python进行后端开发过程中,需要对用户登录信息进行加密,并有一定的安全性要求,于是采用了“国密sm2”进行加密。 二、策略 在每次加密过程中都会首先生成新的公私钥,并存入session 后端生成密钥对和前端...
  • vue中使用SM2加密

    千次阅读 2022-04-18 14:17:28
    vue中使用SM2加密
  • 国密算法SM2加密、SM2解密示例

    千次阅读 2022-07-01 10:20:19
    基于国密算法进行SM2加密和SM2解密的示例为了确保安全,示例中的密钥会使用几个*号进行代替。SM2公钥(长度130):04383**********115EF146FF9E8D5BD9EE04A8799B4A7B49EAB39F02B6572CA8C2AF0C25EA02B77EDA895DBE5A...
  • java sm2 加密 解密

    千次阅读 2021-07-21 16:11:53
    java sm2 加密 解密 maven依赖key 实体工具类 maven依赖 <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.57</...
  • Springboot整合SM2加密的笔记

    千次阅读 2021-07-01 16:52:16
    首先要明白公钥是加密,私钥用来解密。 国密公钥格式:公钥为64位,前后各32位,对应椭圆算法中BigInteger X 和 BigInteger X ,私钥为32位,对应算法中的BigInteger d。 网上的工具类:原文连接...
  • 根据等保要求,密码必须使用SM2加密传输。
  • jmeter-SM2加密

    2022-03-31 13:52:49
    jmeter实现SM2加密
  • Java通用C# SM2加密解密

    2022-08-27 20:55:45
    //加密 string str=""; var Encryptdata = handle.Encrypt(System.Text.Encoding.UTF8.GetBytes(str)); string datac = Hex.ToHexString(Encryptdata); //解密 string str=""; var original = handle.Decrypt(Hex....
  • 根据等保要求,密码使用SM2加密传输。 资源里面有js使用SM2加密方式和后台解密方式,以及所需要的js文件、jar包。
  • 国密加密算法sm2Sm2, a State Secret Encryption Algorithms)
  • 基于Miracl大数运算库实现SM2算法,包含加密和签名算法,纯C语言实现,包含Miracl库手册。提供了Linux平台下的Makefile文件,可直接运行。Windows平台需要重新建立项目工程。
  • sm2加密算法实例_实例说明加密算法

    千次阅读 2020-08-18 01:08:24
    sm2加密算法实例Cryptography, at its most basic, is the science of using codes and ciphers to protect messages. 密码学从根本上讲就是使用代码和密码保护消息的科学。 Encryption is encoding messages with ...
  • sm2加密算法工具类

    2022-07-07 17:11:48
    国密非对称算法sm2工具类项目实战
  • c++国密算法SM2加密解密demo

    千次阅读 2021-08-26 20:51:17
    c++国密算法SM2加密解密一、代码 一、代码 封装和nodejs通讯接口: Encrpt_SM2_new() Decrypt_SM2_new() 加密解密结果可以和nodejs的模块sm-crypto ,加密解密结果可以互相通讯 代码工程下载地址; c++通讯接口...
  • SM2加密解密工具类

    2022-09-06 16:12:33
    SM2加密解密工具类 附带Maven依赖 全代码
  • 国密SM2加密示例(java)

    千次阅读 2021-04-28 16:58:43
    国密SM2加密示例 原始文档 定义参数 SM2创建 生成私钥 生成公钥 公私钥导入导出 代码调用示例 原始文档 定义参数 public static BigInteger n = new BigInteger( "FFFFFFFE" + "FFFFFFFF" + "FFFFFFFF" + ...
  • 项目的复杂度在于国密的非对称加密算法SM2的Java及JS实现。 Java版比较好办,较新版本的bouncycastle就支持了SM2/SM3/SM4,麻烦在于JS版,找了很多都有问题,直到遇到了这个项目:...
  • vue-sm2加密解密

    千次阅读 2022-05-26 10:31:24
    2.加密: const sm2 = require('sm-crypto').sm2 constcipherMode= 1 ;// 1 - C1C3C2,0 - C1C2C3,默认为1 const publicKey = "04fffce60f2a91ac4c4bcc3aaf5a06b7d8eef2ea2d4ddf22bfb5137006307185234f8a61e671446...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,949
精华内容 1,979
关键字:

sm2加密