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

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

后端(Springboot)

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

        
        
            cn.hutool
            hutool-all
            5.3.10
        

        
        
            org.bouncycastle
            bcprov-jdk15to18
            1.68
        

(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密钥出错");
        }
   

你可能感兴趣的:(前端,html,javascript,json,typescript)