Vue + Springboot 前后端完整使用国密算法 SM2 数据加密 传输 交互 完整解决方案

本文介绍了如何使用Vue和Springboot实现前后端完整的国密算法SM2加密数据传输。在Springboot后端,通过添加依赖、创建SM2功能方法和拦截器来解密请求并加密响应。前端Vue部分则处理加密请求和解密响应数据,确保数据安全交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目外网部署的时候经常会有要求数据加密传输的情况,特别是企事业单位的项目,另为安全或者红头文件计,经常要求使用国密算法,因为涉及交互,所以使用SM2非对称加密。

后端(Springboot)

(1)所需主要依赖(其他如有缺失自行百度即可):

        <!-- hutool工具类 -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.10</version>
        </dependency>

        <!-- 第三方加密功能依赖 -->
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15to18</artifactId>
            <version>1.68</version>
        </dependency>

(2)SM2功能方法的创建

博主这里在后端把相关的加解密功能做成了功能接口,所以这里直接展示service实现类的代码,里边的统一返回参数改成自己的类型即可

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 com.ruoyi.common.constant.EncryptConstant;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.encrypt.dto.ApiEncryptInfoDTO;
import com.ruoyi.common.utils.encrypt.dto.Result;
import com.ruoyi.common.utils.encrypt.service.ApiEncryptService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.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;
import org.springframework.stereotype.Service;

/**
 * 加解密相关功能实现类
 *
 * @author gbx
 */
@Service
@Slf4j
public class ApiEncryptServiceImpl implements ApiEncryptService {

    /**
     * SM2加密
     *
     * @param dto 包含加解密相关参数信息的实体
     * @return 处理结果
     */
    @Override
    public Result encrypt2Data(ApiEncryptInfoDTO dto) {
        String publicKey = dto.getPublicKey();
        // 若为空,使用默认
        if (StringUtils.isBlank(publicKey)) {
            publicKey = EncryptConstant.PUBLIC_KEY;
        }
        String data = dto.getData();
        //创建sm2 对象
        SM2 sm2 = getSM2(null, publicKey);
        String dataHex = sm2.encryptBcd(data, KeyType.PublicKey);
        dto.setDataHex(dataHex);
        return new Result().ok(dto);
    }

    /**
     * SM2解密
     *
     * @param dto 包含加解密相关参数信息的实体
     * @return 处理结果
     */
    @Override
    public Result decrypt2Data(ApiEncryptInfoDTO dto) {
        String privateKey = dto.getPrivateKey();
        // 若为空,使用默认
        if (StringUtils.isBlank(privateKey)) {
            privateKey = EncryptConstant.PRIVATE_KEY;
        }
        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);
            throw new BaseException("SM2解密失败");
        }
        return new Result().ok(dto);
    }

    /**
     * SM4加密
     *
     * @param dto 包含加解密相关参数信息的实体
     * @return 处理结果
     */
    @Override
    public Result encrypt4Data(ApiEncryptInfoDTO dto) {
        //指定的密钥
        String key = dto.getKey();
        // 若为空,使用默认
        if (StringUtils.isBlank(key)) {
            key = EncryptConstant.SM4_KEY;
        }
        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);
            throw new BaseException("SM4加密数据异常");
        }
        return new Result().ok(dto);
    }

    /**
     * SM4解密
     *
     * @param dto 包含加解密相关参数信息的实体
     * @return 处理结果
     */
    @Override
    public Result decrypt4Data(ApiEncryptInfoDTO dto) {
        //指定的密钥
        String key = dto.getKey();
        // 若为空,使用默认
        if (StringUtils.isBlank(key)) {
            key = EncryptConstant.SM4_KEY;
        }
        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);
            throw new BaseException("SM4解密数据异常");
        }
        return new Result().ok(dto);
    }

    /**
     * 生成一对 C1C2C3 格式的SM2密钥
     *
     * @return 处理结果
     */
    @Override
    public Result 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);
            throw new BaseException("获取SM2密钥出错");
        }
   
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值