国密算法SM2加密解密

一、依赖包

        <!-- 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());
    }
}

  • 7
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 国密算法SM2是我国自主设计的一种非对称加密算法,主要用于数字签名和密钥交换。随着信息安全需求的增强,SM2算法在我国的应用越来越广泛。 SM2算法的C语言实现可以通过调用相关库函数来完成。通常使用的是开源的RSA和EC库来实现SM2算法。以下是可能的实现步骤: 1. 引入相关库:在C语言代码中引入SM2算法所需要的RSA和EC库函数。 2. 生成密钥对:使用EC库函数生成SM2算法所需的密钥对。密钥对包括公钥和私钥,用于加密和解密数据。 3. 数据加密:使用RSA库函数对需要加密的数据进行加密处理。加密过程中使用公钥对数据进行加密,得到密文。 4. 数据解密:使用RSA库函数对密文进行解密处理。解密过程中使用私钥对密文进行解密,得到明文数据。 5. 数字签名:使用EC库函数对数据进行数字签名。数字签名过程中使用私钥对数据进行签名,得到签名结果。 6. 验证签名:使用EC库函数对签名结果进行验证。验证过程中使用公钥对签名结果进行验证,确定签名的有效性。 以上只是实现SM2算法的大致步骤,具体实现还需要根据具体需求进行调整和补充。此外,为了保证算法的安全性,还需要对密钥进行安全的管理与存储。 总之,通过调用相关库函数,可以实现SM2算法的C语言实现,为信息安全提供了有效的保障。 ### 回答2: 国密算法SM2是我国自主研发的一种基于椭圆曲线密码学的公钥加密算法,用于实现数字签名、密钥交换和加密等功能。 要实现SM2算法的C语言代码,可以按照以下步骤进行: 1. 导入相关的库文件:在C语言中,需要导入相关的库文件来支持椭圆曲线运算和密码学算法实现。例如,在OpenSSL库中,可以使用`#include <openssl/sm2.h>`来导入SM2算法相关的头文件。 2. 生成密钥对:在SM2算法中,需要首先生成一对公私钥对。可以使用库中的API函数,如`EVP_PKEY *gen_keypair();`来生成一个SM2密钥对。 3. 进行数字签名:假设要对某个消息进行数字签名,可以使用API函数`int sm2_sign(const EVP_MD *md, const unsigned char *msg, size_t msglen, const unsigned char *id, size_t idlen, const EVP_PKEY *pkey, unsigned char *sig, size_t *siglen);`。在函数参数中,md表示哈希算法、msg表示消息、id表示用户标识、pkey表示私钥,sig表示签名输出。 4. 验证数字签名:使用API函数`int sm2_verify(const EVP_MD *md, const unsigned char *msg, size_t msglen, const unsigned char *id, size_t idlen, const EVP_PKEY *pkey, const unsigned char *sig, size_t siglen);`来验证数字签名。在函数参数中,md表示哈希算法、msg表示消息、id表示用户标识、pkey表示公钥,sig表示需要验证的签名。 以上为简要的SM2算法C语言实现的步骤,具体的代码实现需要结合具体的库文件和API函数进行。希望以上回答对你有帮助! ### 回答3: 国密算法SM2是由中国密码学家自主研发的一种非对称加密算法,主要用于数字签名和密钥交换。C语言是一种广泛应用于系统编程和嵌入式开发的编程语言,具有良好的性能和跨平台特性。实现国密算法SM2的C语言版本,可以使算法在不同的硬件和操作系统上运行。 实现SM2算法的C语言版本需要以下几个核心步骤: 1. 导入必要的头文件和库:C语言中,需要导入相关的头文件和库才能使用算法所需的函数和数据类型。 2. 生成密钥对:使用C语言的随机数生成函数生成SM2算法所需的私钥和公钥。 3. 数据加密和解密:使用C语言的加密和解密函数调用SM2算法中的相应函数进行数据的加密和解密。 4. 数字签名和验证:使用C语言的哈希函数计算消息摘要,然后调用SM2算法中的数字签名和验证函数进行签名和验证操作。 5. 密钥交换:通过调用SM2算法中的密钥交换函数,实现双方之间的密钥交换。 6. 进行测试和调试:使用C语言的单元测试框架对实现的算法进行测试和调试,确保算法的正确性和稳定性。 总结来说,实现国密算法SM2的C语言版本需要导入相关的头文件和库,生成密钥对,进行数据加密和解密,实现数字签名和验证,以及实现密钥交换等功能。通过测试和调试保证算法的正确性和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值