终于把前后端sm加解密以及加签验证调通了。

这篇具有很好参考价值的文章主要介绍了终于把前后端sm加解密以及加签验证调通了。。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

终于把前后端sm加解密以及加签验证调通了!

	领导要求我对项目的数据传输安全考虑下,因此就想到了对敏感字段做加密和对请求、响应做数字签名验证。网上看了很多文章,可能是因为我对加密这块不了解,感觉都比较乱。所以前前后后花了4天才把前后端调通。特地写一篇文章记录下流程。这里使用的是sm国密算法。不对的地方请读者评论指出。

1.简单说明:

  • 前端使用sm-crypto库

  • 后端加密库使用bc库,架构上使用aop,注解等实现

2.具体实现-前端

  • 加密流程:生成一个对称密钥,对每个字段使用sm4对称加密,然后进行base64编码。对称密钥使用sm2非对称加密
// 生成对称密钥
export function genSM4SymmetricKey(){
    let sl = "abcdef0123456789";
    let bl=""
    for (let i = 0; i < 16; i++) {
        bl = bl.concat(sl.charAt(Math.floor(Math.random() * 16)));
    }
    return bl.toString();
}
// 字段sm4加密再转base64
export function encryptovalue(value,symmetricKey){
    let key=StringToHex(symmetricKey)
    return Base64.btoa( HexToString(sm4.encrypt( value,key)) );
}
// 对象添加加密后的对称密钥属性
export function addSm4SymmetricKey(symmetricKey,obj){
    // 加密对称密钥,前面加04
    sm2.doEncrypt(symmetricKey,publicKey,cipherMode);
    obj["sm4SymmetricKey"]="04"+symmetricKey
    return obj
}
  • 解密流程:对后端响应的数据对象中的加密字段进行base64解码,sm2解密解出对称密钥,再使用对称密钥进行sm4解密
// 解密对称密钥
export function decryptSm4SymmetricKey(sm4SymmetricKey){
    // 去除开头的04
    sm4SymmetricKey = sm4SymmetricKey.substr(2)
    return  sm2.doDecrypt(sm4SymmetricKey,privateKey);
}
// 字段sm4解密
export function decryptovalue(value,symmetricKey){
    value=base64ToHex(value)
    console.log("value=",value)
    let des = sm4.decrypt(value,symmetricKey)
    console.log("base64解码后解密:",des)
    return des
}
  • 加签流程:加密前进行加签,对象key排序后,拼接成key=value&key=value&key=value…的形式,再进行sm2数字签名。
export function sm2Signature(obj){
    let str = signatureStr(obj)
    // 签名
    let sigValueHex4 = sm2.doSignature(str, privateKey, {
        hash:true,
        der:true,
    })
    console.log("签名串:",sigValueHex4)
    return sigValueHex4;
}
  • 验签流程:解密之后要进行验签,将解密后的对象key排序后,拼接成key=value&key=value&key=value…的形式,进行sm2签名验证
export function sm2VerifySignature(obj){
    console.log(obj)
    let signature = obj.signature
    delete obj["sm4SymmetricKey"]
    delete obj["signature"]
    let str = signatureStr(obj)
    let verifyResult = sm2.doVerifySignature(str, signature, publicKey, {
        der:true,
        hash: true,
    })
    console.log("验签结果:",verifyResult)
    return verifyResult
}
  • 测试页面代码
<template>
  <input type="text" v-model="objfront.address" />
  <input type="text" v-model="objfront.password" />
  <button @click="sm">加密</button>
  <button @click="send">发送</button>
  <div>后端返回</div>
  <input type="text" v-model="decrespData.address" />
  <input type="text" v-model="decrespData.password" />
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
}
</script>
<script setup>
import {onBeforeMount, onMounted,ref,reactive} from "vue";
import {sm2,sm4} from "sm-crypto";
import {Base64} from "js-base64";
import {test} from "@/api/test";
import {
  decryptovalue,
  decryptSm4SymmetricKey,
  encryptovalue,
  randomString,
  sm2Signature, sm2VerifySignature
} from "../utils/cryptTools";
let obj=reactive({
})
let objfront=reactive({
  name:'1',
  age:'12',
  address:"1",
  password:"2",
  timeStamp:"",
  nonceStr:""
})
let decrespData=ref({
})
//sm2的加解密时有两种方式即0——C1C2C3、1——C1C3C2,前后端需要统一
const cipherMode = 1
const publicKey = '04bdf29de4e09f8ddd484035879705530e7af03b431370fa7a3734dbf3b9ad937a640b90d0824e4ffad681d77363f4ddb15a574afc86a0a289902dafeca73712bc'
function  StringToHex(str) {
  if (str == '')
    return '';
  let hex = [];
  for (var i = 0; i < str.length; i++) {
    hex.push((str.charCodeAt(i)).toString(16));
  }
  return hex.join('');
}
function HexToString(str1) {
  let hex = str1.toString();
  let str = "";
  for (let n = 0; n < hex.length; n += 2) {
    str += String.fromCharCode(parseInt(hex.substr(n, 2), 16));
  }
  return str;
}
function genSM4SymmetricKey(){
  let sl = "abcdef0123456789";
  let bl=""
  for (let i = 0; i < 16; i++) {
    bl = bl.concat(sl.charAt(Math.floor(Math.random() * 16)));
  }
  return bl.toString();
}

function sm(){
  // 生成时间戳
  objfront.timeStamp = new Date().getTime();
  // 生成随机字符串
  objfront.nonceStr = randomString(16)
  // 前端业务对象放入请求对象
  obj = JSON.parse(JSON.stringify(objfront));
  // 签名放入对象
  obj["signature"] = sm2Signature(objfront)

  let symmetricKey = genSM4SymmetricKey();
  // 对称加密
  obj.password = encryptovalue( objfront.password,symmetricKey );
  obj.address = encryptovalue( objfront.address,symmetricKey );
  //  加密对称密钥,前面加04
  symmetricKey = sm2.doEncrypt(symmetricKey,publicKey,cipherMode);
  obj["sm4SymmetricKey"]="04"+symmetricKey
}
function send(){
  test(obj).then((res)=>{
    let data = res.data;
    decrespData.value = res.data
    // 解出对称密钥
    let symmetricKey = decryptSm4SymmetricKey(data.sm4SymmetricKey);
    console.log("对称密钥:",symmetricKey)
    // 解密字段
    decrespData.value.address = decryptovalue(data.address,StringToHex(symmetricKey))
    decrespData.value.password = decryptovalue(data.password,StringToHex(symmetricKey))
    // 验签
    if(!sm2VerifySignature(decrespData.value)){
      return
    }
    console.log("成功!")
  })

}
</script>

3.具体实现-后端

  • 创建注解@Crypt
@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})              // 可以作用在类上和方法和字段上。
@Retention(RetentionPolicy.RUNTIME)
public @interface Crypt {
}
@Data
public class User extends BaseObject {

    private String name;

    @Crypt
    private String password;

    private String age;

    @Crypt
    private String address;

}
@Api(tags = "用户控制器")
@ApiModel
@RestController
@ResponseBody
@RequestMapping("/pa")
public class UserController {

    @Crypt
    @PostMapping("test")
    public Result<User> test(@RequestBody User user){
        User newUser = new User();
        newUser.setName("后端返回");
        newUser.setPassword(user.getPassword());
        newUser.setAddress(user.getAddress());
        newUser.setAge(user.getAge());
        return Result.success(newUser);
    }

    @Crypt
    @GetMapping("testget")
    public Result<String> testget(){
        return Result.success("hello");
    }
}

创建切面类文章来源地址https://www.toymoban.com/news/detail-620015.html

package com.lxls.personalachievement.common.safe.aop;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.Maps;
import com.google.common.io.BaseEncoding;
import com.lxls.personalachievement.common.result.Result;
import com.lxls.personalachievement.common.result.ResultCode;
import com.lxls.personalachievement.common.safe.SMConfig;
import com.lxls.personalachievement.common.safe.annotation.Crypt;
import com.lxls.personalachievement.tools.sm.BytesUtil;
import com.lxls.personalachievement.tools.sm.KeyUtil;
import com.lxls.personalachievement.tools.sm.SMUtil;
import com.lxls.personalachievement.tools.smnew.SM2Util;
import org.apache.commons.codec.binary.Base64;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.util.encoders.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @author: WangQC
 * @date 2023/2/10 13:34
 */
@Order(Ordered.HIGHEST_PRECEDENCE)
@Aspect
@Component
public class AspectSafe {
    Logger log = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private SMConfig smConfig;
    @Autowired
    private SMUtil smUtil;

    // 定义切点(在Crypt切点或者controller方法上)
    @Pointcut("@annotation(com.lxls.personalachievement.common.safe.annotation.Crypt)")
    public void pt() {
    }

    //环绕通知,方法前后都可以进行增强
    @Around("pt()")
    public Object crypt(ProceedingJoinPoint joinPoint) throws Throwable {
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();
        if("GET".equals(request.getMethod())){
            return joinPoint.proceed();
        }
        Result responseObj = null;
        try {
            Object arg = joinPoint.getArgs()[0];
            // 获取参数
            Object requestObj = joinPoint.getArgs()[0];
            // 解密
            Object[] decryptObj  = handleDecrypt(requestObj);
            if( decryptObj[0] instanceof  Result ){
                // 返回对象为Result,则表示出错应当返回前端
                return decryptObj[0];
            }
            // 验签
            if(!handleSignatureVerificate(requestObj)){
                // 验签失败返回
                return Result.failed(ResultCode.SIGNATUR_ERROR,ResultCode.SIGNATUR_ERROR.getMsg());
            }
            // 调用执行方法
            responseObj = (Result) joinPoint.proceed(decryptObj);
            // 加签
            responseObj = handleSign(responseObj.getData());
            // 返回加密
            handleEncrypt(responseObj.getData());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
            log.error("SecureFieldAop处理出现异常{}", e);
            return Result.failed(ResultCode.CRYPTOERROR,ResultCode.CRYPTOERROR.getMsg());
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            log.error("SecureFieldAop处理出现异常{}", throwable);
            return Result.failed(ResultCode.CRYPTOERROR,ResultCode.CRYPTOERROR.getMsg());
        }
        return responseObj;
    }

    // 解密处理
    private Object[] handleDecrypt(Object requsetObj) throws IllegalAccessException {
        // 如果是post或put才执行
        log.debug("待解密参数:{}",requsetObj);
        if (Objects.isNull(requsetObj)) {
            return null;
        }
        String symmetricKey=null;
        Field[] superfields = requsetObj.getClass().getSuperclass().getDeclaredFields();
        Field[] fields = requsetObj.getClass().getDeclaredFields();
        for (Field field : superfields) {
            if("sm4SymmetricKey".equals(field.getName())){
                // 解密sm4密钥
                field.setAccessible(true);
                String encString=(String)field.get(requsetObj);
                if( !StringUtils.hasText(encString)){
                    Object [] objects=new Object[]{Result.failed(ResultCode.NOSYMMETRICKEY,ResultCode.NOSYMMETRICKEY.getMsg())};
                    return objects;
                }
                byte[] bytes = BytesUtil.hexToBytes(encString);
                symmetricKey = smUtil.sm2Decrypt(smConfig.getPrivateKey(),bytes);
                log.debug("解密出的对称密钥:{}",symmetricKey);
                break;
            }
        }
        for (Field field : fields) {
            boolean hasSecureField = field.isAnnotationPresent(Crypt.class);
            if (hasSecureField) {
                field.setAccessible(true);
                Object o = field.get(requsetObj);
                String s = smUtil.sm4Decrypt(symmetricKey, Base64.decodeBase64((String) field.get(requsetObj)));
                field.set(requsetObj,s);
            }
        }
        log.debug("解密后请求对象:{}",requsetObj);
        Object [] objects=new Object[]{requsetObj};
        return objects;
    }
    // 加密处理
    private Object handleEncrypt(Object responseObj) throws IllegalAccessException, UnsupportedEncodingException {
        log.debug("待加密参数,{}",responseObj);
        if (Objects.isNull(responseObj)) {
            return null;
        }
        // 获取请求参数对象
        Class<?> requestObjClass = responseObj.getClass();
        // 获取类上的注解,如果存在,则整个对象属性都进行加密
        Crypt annotation = requestObjClass.getAnnotation(Crypt.class);
        // 获取字段
        Field[] fields = requestObjClass.getDeclaredFields();
        Field[] superFields = requestObjClass.getSuperclass().getDeclaredFields();
        // 生成sm4 key
        String sm4SymmetricKey = KeyUtil.genSM4SymmetricKey();
        log.debug("待加密的对称密钥:{}",sm4SymmetricKey);
        // 加密对称密钥
        String sm4SymmetricKeyEncrypt = smUtil.sm2Encrypt(smConfig.getPublicKey(), sm4SymmetricKey);

        for(Field field : superFields){
            if("sm4SymmetricKey".equals(field.getName())){
                field.setAccessible(true);
                field.set(responseObj,sm4SymmetricKeyEncrypt);
                break;
            }
        }
        if (annotation == null) {
            // 对每个字段进行遍历,有注解则进行加密
            for (Field field : fields) {
                if (field.getAnnotation(Crypt.class) == null) {
                    continue;
                } else {
                    // 加密字段
                    field.setAccessible(true);
                    String plaintextValue = (String) field.get(responseObj);
                    byte[] bytes = smUtil.sm4Encrypt(sm4SymmetricKey, plaintextValue);
                    field.set(responseObj, Base64.encodeBase64String(bytes));
                }
            }
        } else {
            // 类上注解,对类中的所有字段进行加密
            for (Field field : fields) {
                // 加密字段
                field.setAccessible(true);
                String plaintextValue = (String) field.get(responseObj);
                byte[] bytes = smUtil.sm4Encrypt(sm4SymmetricKey, plaintextValue); // 用sm4加密字段
                field.set(responseObj, Base64.encodeBase64String(bytes));
            }
        }
        log.debug("加密后参数,{}",responseObj);
        return responseObj;
    }

    // 验签处理
    private Boolean handleSignatureVerificate(Object requsetObj) throws IllegalAccessException {
        /**
         * 1.将对象转为map,
         * 2.删除签名和对称密钥的key
         * 3.根据key进行排序
         * 4.验签
         */
        String signature=null;
        Field[] superfields = requsetObj.getClass().getSuperclass().getDeclaredFields();
        Field[] fields = requsetObj.getClass().getDeclaredFields();
        for (Field field : superfields) {
            if("signature".equals(field.getName())){
                // 获取签名串
                field.setAccessible(true);
                signature=(String)field.get(requsetObj);
                break;
            }
        }
        String str = generateSignatureStr(requsetObj);
        log.debug("验签待签名串,{}",str);
        boolean b = SM2Util.verify(smConfig.getPublicKey(),Hex.toHexString(str.getBytes()), signature);
        return b;
    }

    // 加签处理
    private Result handleSign(Object responseObj) throws IllegalAccessException, CryptoException {
        /**
         * 1.明文参与加签
         * 2.添加随机字符串和时间戳
         * 3.签名放入返回对象
         */
        Long timeStamp=null;
        String nonceStr=null;
        Field[] superfields = responseObj.getClass().getSuperclass().getDeclaredFields();
        Field[] fields = responseObj.getClass().getDeclaredFields();
        for (Field field : superfields) {
            if("nonceStr".equals(field.getName())){
                field.setAccessible(true);
                // 生成随机字符串
                nonceStr = KeyUtil.createNonceStr(16);
                field.set(responseObj,nonceStr);
                continue;
            }
            if("timeStamp".equals(field.getName())){
                field.setAccessible(true);
                // 生成时间戳
                timeStamp = System.currentTimeMillis();
                field.set(responseObj,timeStamp);
            }
        }
        // 生成待签名串
        String str = generateSignatureStr(responseObj);
        log.debug("加签待签名串:{}",str);
        // 签名
        String signature = SM2Util.sign(smConfig.getPrivateKey(), Hex.toHexString(str.getBytes()));
        // 放入对象
        for (Field field : superfields) {
            if("signature".equals(field.getName())){
                field.setAccessible(true);
                field.set(responseObj,signature);
                break;
            }
        }
        return Result.success(responseObj);
    }

    // 生成待签名串
    private String generateSignatureStr(Object obj){
        BeanMap beanMap = BeanMap.create(obj);
        Map<String, Object> map = Maps.newHashMap(beanMap);
        map.remove("sm4SymmetricKey");
        map.remove("signature");
        return KeyUtil.sortMapToSTring(map);
    }
}
  • sm工具类
package com.lxls.personalachievement.tools.sm;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERSequence;
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.jcajce.spec.SM2ParameterSpec;
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 org.springframework.stereotype.Component;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.math.BigInteger;
import java.security.Key;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
import java.util.Arrays;

@Component
public class SMUtil {
public static final int RS_LEN = 32;
    private static final String SIGNATURE_PARAM = "SM3withSM2";
    private static final String PROV_NAME = BouncyCastleProvider.PROVIDER_NAME;
    //SM2曲线名称
    private static final String CURVE_NAME = "sm2p256v1";
    //SM2相关参数
    private static final X9ECParameters x9ECParameters = GMNamedCurves.getByName(CURVE_NAME);
    //椭圆曲线参数规格
    private static final ECParameterSpec ecParameterSpec = new ECParameterSpec(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN(), x9ECParameters.getH());

    private static final String CIPHER_PARAM = "SM4";
    private static final String MODE_PARAM = "SM4/ECB/PKCS7Padding";
    
    //只需加载一次
    static {
        if (Security.getProperty(PROV_NAME) == null) {
            Security.addProvider(new BouncyCastleProvider());
        }
    }
    
    private 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), ecParameterSpec);
        //通过椭圆曲线公钥规范,创建出椭圆曲线公钥对象(可用于SM2加密及验签)
        return new BCECPublicKey("EC", ecPublicKeySpec, BouncyCastleProvider.CONFIGURATION);
    }
   
    private static byte[] innerSM2Encrypt(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 arrayOfBytes;
    }
    /**
     * SM2加密入口
     */
   public String sm2Encrypt(String hexPublicKey, String plainText) {
        //生产bc公钥对象
        BCECPublicKey publicKey = getECPublicKeyByPublicKeyHex(hexPublicKey);
        //加密
        try {
            byte[] encText = innerSM2Encrypt(publicKey, plainText,1);
            return Hex.toHexString(encText);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
   
   private static BCECPrivateKey getBCECPrivateKeyByPrivateKeyHex(String privateKeyHex) {
        //将十六进制私钥字符串转换为BigInteger对象
        BigInteger d = new BigInteger(privateKeyHex, 16);
        //通过私钥和私钥域参数集创建椭圆曲线私钥规范
        ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(d, ecParameterSpec);
        //通过椭圆曲线私钥规范,创建出椭圆曲线私钥对象(可用于SM2解密和签名)
        return new BCECPrivateKey("EC", ecPrivateKeySpec, BouncyCastleProvider.CONFIGURATION);
    }
    
    private static byte[] innerSM2Decrypt(BCECPrivateKey privateKey, byte[] cipherData, int modeType) throws Exception {
        //解密模式
        SM2Engine.Mode mode = SM2Engine.Mode.C1C3C2;
        if (modeType != 1)
            mode = SM2Engine.Mode.C1C2C3;
        //通过私钥对象获取私钥的基本域参数。
        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);
        try {
            //通过解密引擎对密文字节串进行解密
            byte[] arrayOfBytes = sm2Engine.processBlock(cipherData, 0, cipherData.length);
            //将解密后的字节串转换为utf8字符编码的字符串(需要与明文加密时字符串转换成字节串所指定的字符编码保持一致)
            return arrayOfBytes;
        } catch (Exception e) {
            System.out.println("SM2解密时出现异常" + e.getMessage());
        }
        return null;
    }
    /**
     * SM2解密入口
     */
    public String sm2Decrypt(String hexPrivateKey, byte[] encBytes) {
        try{
            BCECPrivateKey privateKey = getBCECPrivateKeyByPrivateKeyHex(hexPrivateKey);
            byte[] decResult = innerSM2Decrypt(privateKey, encBytes,1);
            return new String(decResult);
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }
    
    private static byte[] signature(byte[] src, BCECPrivateKey sm2Key) throws Exception {
        byte[] dest = null;
        Signature signature = Signature.getInstance(SIGNATURE_PARAM, PROV_NAME);
        signature.setParameter(new SM2ParameterSpec("lxls".getBytes()));
        signature.initSign(sm2Key);
        signature.update(src);
        dest = signature.sign();
        return ans1ToRS(dest);
    }
    
    private static byte[] ans1ToRS(byte[] rsDer) {
        ASN1Sequence seq = ASN1Sequence.getInstance(rsDer);
        byte[] r = bigIntToFixexLengthBytes(ASN1Integer.getInstance(seq.getObjectAt(0)).getValue());
        byte[] s = bigIntToFixexLengthBytes(ASN1Integer.getInstance(seq.getObjectAt(1)).getValue());
        byte[] result = new byte[RS_LEN * 2];
        System.arraycopy(r, 0, result, 0, r.length);
        System.arraycopy(s, 0, result, RS_LEN, s.length);
        return result;
    }
    
    private static byte[] bigIntToFixexLengthBytes(BigInteger rOrS) {
        // for sm2p256v1, n is 00fffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123,
        // r and s are the result of mod n, so they should be less than n and have length<=32
        byte[] rs = rOrS.toByteArray();
        if (rs.length == RS_LEN) return rs;
        else if (rs.length == RS_LEN + 1 && rs[0] == 0) return Arrays.copyOfRange(rs, 1, RS_LEN + 1);
        else if (rs.length < RS_LEN) {
            byte[] result = new byte[RS_LEN];
            Arrays.fill(result, (byte) 0);
            System.arraycopy(rs, 0, result, RS_LEN - rs.length, rs.length);
            return result;
        } else {
            throw new RuntimeException("err rs: " + Hex.toHexString(rs));
        }
    }
    /**
     * SM2加签入口
     */
    public byte[] sm2Sign(String hexPrivateKey, String sortedString) {
        try{
            BCECPrivateKey privateKey = getBCECPrivateKeyByPrivateKeyHex(hexPrivateKey);
            byte[]signResult = signature(sortedString.getBytes(), privateKey);
            return signResult;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }
    
    private static byte[] rsPlainByteArrayToAsn1(byte[] sign) {
        if (sign.length != RS_LEN * 2) throw new RuntimeException("err rs. ");
        BigInteger r = new BigInteger(1, Arrays.copyOfRange(sign, 0, RS_LEN));
        BigInteger s = new BigInteger(1, Arrays.copyOfRange(sign, RS_LEN, RS_LEN * 2));
        ASN1EncodableVector v = new ASN1EncodableVector();
        v.add(new ASN1Integer(r));
        v.add(new ASN1Integer(s));
        try {
            return new DERSequence(v).getEncoded("DER");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    
    private static boolean verifySignature(byte[] src, byte[] sign, BCECPublicKey sm2Key) throws Exception {
        boolean res;
        try {
            byte[] sign_asn1 = rsPlainByteArrayToAsn1(sign);
            Signature signature = Signature.getInstance(SIGNATURE_PARAM, PROV_NAME);
            signature.setParameter(new SM2ParameterSpec("lxls".getBytes()));
            signature.initVerify(sm2Key);
            signature.update(src);
            res = signature.verify(sign_asn1);
        }catch (Exception e){
            System.out.println("发生异常:"+e);
            return false;
        }
        return res;
    }
    /**
     * SM2验签入口
     */
    public boolean sm2SignValidate(String hexPublicKey, byte[] value, String sortedString) {
        try{
            BCECPublicKey publicKey = getECPublicKeyByPublicKeyHex(hexPublicKey);
            return verifySignature(sortedString.getBytes(), value, publicKey);
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }
    
    private static Key generateSm4Key(byte[] key) {
        Key sm4Key = new SecretKeySpec(key, CIPHER_PARAM);
        return sm4Key;
    }

    private static byte[] innerSM4Encrypt(byte[] src, byte[] key) throws Exception{
        byte[] dest = null;
        Cipher cipher = Cipher.getInstance(MODE_PARAM, PROV_NAME);
        Key sm4Key = generateSm4Key(key);

        cipher.init(Cipher.ENCRYPT_MODE, sm4Key);
        dest = cipher.doFinal(src);
        return dest;
}

    private static byte[] innerSM4Decrypt(byte[] key,byte[] src) throws Exception{
        byte[] dest = null;
        Cipher cipher = Cipher.getInstance(MODE_PARAM, PROV_NAME);
        Key sm4Key = generateSm4Key(key);
        cipher.init(Cipher.DECRYPT_MODE, sm4Key);
        dest = cipher.doFinal(src);
        return dest;
    }
    
    /**
     * SM4加密入口
     */
    public byte[] sm4Encrypt(String sm4Key, String plainText) {
        try{
            return innerSM4Encrypt(plainText.getBytes(), sm4Key.getBytes());
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }
    
    /**
     * SM4解密入口
     */
    public String sm4Decrypt(String sm4Key, byte[] encBytes) {
        try{
            return new String(innerSM4Decrypt(sm4Key.getBytes(), encBytes));
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }
}
  • 签名验签上面的工具类和前端通不过,所以又找了一个工具类,因此,签名和验签使用的是下面的工具类
package com.lxls.personalachievement.tools.smnew;

import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;

import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;

/**
 * 1. @description: SM2工具类
 * 2. @author: xh
 * 3. @time: 2022/3/18
 */
@Slf4j
public class SM2Util {

    /**
     * 生成SM2公私钥对
     * @return
     */
    private static AsymmetricCipherKeyPair genKeyPair0() {
        //获取一条SM2曲线参数
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");

        //构造domain参数
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                sm2ECParameters.getG(), sm2ECParameters.getN());

        //1.创建密钥生成器
        ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();

        //2.初始化生成器,带上随机数
        try {
            keyPairGenerator.init(new ECKeyGenerationParameters(domainParameters, SecureRandom.getInstance("SHA1PRNG")));
        } catch (NoSuchAlgorithmException e) {
            log.error("生成公私钥对时出现异常:", e);
//            e.printStackTrace();
        }

        //3.生成密钥对
        AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();
        return asymmetricCipherKeyPair;
    }

    /**
     * 生成公私钥对(默认压缩公钥)
     * @return
     */
    public static SMKeyPair genKeyPair() {
        return genKeyPair(true);
    }

    /**
     * 生成公私钥对
     * @param compressedPubKey  是否压缩公钥
     * @return
     */
    public static SMKeyPair genKeyPair(boolean compressedPubKey) {
        AsymmetricCipherKeyPair asymmetricCipherKeyPair = genKeyPair0();

        //提取公钥点
        ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();
        //公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥,04的时候,可以去掉前面的04
        String pubKey = Hex.toHexString(ecPoint.getEncoded(compressedPubKey));

        BigInteger privatekey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
        String priKey = privatekey.toString(16);

        SMKeyPair keyPair = new SMKeyPair(priKey, pubKey);
        return keyPair;
    }

    /**
     * 私钥签名
     * @param privateKey    私钥
     * @param content       待签名内容
     * @return
     */
    public static String sign(String privateKey, String content) throws CryptoException {
        //待签名内容转为字节数组
        byte[] message = Hex.decode(content);

        //获取一条SM2曲线参数
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
        //构造domain参数
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                sm2ECParameters.getG(), sm2ECParameters.getN());

        BigInteger privateKeyD = new BigInteger(privateKey, 16);
        ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);

        //创建签名实例
        SM2Signer sm2Signer = new SM2Signer();

        //初始化签名实例,带上ID,国密的要求,ID默认值:1234567812345678
        try {
            sm2Signer.init(true, new ParametersWithID(new ParametersWithRandom(privateKeyParameters, SecureRandom.getInstance("SHA1PRNG")), Strings.toByteArray("1234567812345678")));
        } catch (NoSuchAlgorithmException e) {
            log.error("签名时出现异常:", e);
        }
        sm2Signer.update(message, 0, message.length);
        //生成签名,签名分为两部分r和s,分别对应索引0和1的数组
        byte[] signBytes = sm2Signer.generateSignature();

        String sign = Hex.toHexString(signBytes);

        return sign;
    }

    /**
     * 将R或者S修正为固定字节数
     * @param rs
     * @return
     */
    private static byte[] modifyRSFixedBytes(byte[] rs) {
        int length = rs.length;
        int fixedLength = 32;
        byte[] result = new byte[fixedLength];
        if (length < 32) {
            System.arraycopy(rs, 0, result, fixedLength - length, length);
        } else {
            System.arraycopy(rs, length - fixedLength, result, 0, fixedLength);
        }
        return result;
    }

    /**
     * 验证签名
     * @param publicKey     公钥
     * @param content       待签名内容
     * @param sign          签名值
     * @return
     */
    public static boolean verify(String publicKey, String content, String sign) {
        //待签名内容
        byte[] message = Hex.decode(content);
        byte[] signData = Hex.decode(sign);

        // 获取一条SM2曲线参数
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
        // 构造domain参数
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                sm2ECParameters.getG(),
                sm2ECParameters.getN());
        //提取公钥点
        ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(publicKey));
        // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
        ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);
        //创建签名实例
        SM2Signer sm2Signer = new SM2Signer();
        ParametersWithID parametersWithID = new ParametersWithID(publicKeyParameters, Strings.toByteArray("1234567812345678"));
        sm2Signer.init(false, parametersWithID);
        sm2Signer.update(message, 0, message.length);
        //验证签名结果
        boolean verify = sm2Signer.verifySignature(signData);
        return verify;
    }

    /**
     * SM2加密算法
     * @param publicKey     公钥
     * @param data          数据
     * @return
     */
    public static String encrypt(String publicKey, String data){
        // 获取一条SM2曲线参数
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
        // 构造domain参数
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                sm2ECParameters.getG(),
                sm2ECParameters.getN());
        //提取公钥点
        ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(publicKey));
        // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
        ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);

        SM2Engine sm2Engine = new SM2Engine();
        sm2Engine.init(true, new ParametersWithRandom(publicKeyParameters, new SecureRandom()));

        byte[] arrayOfBytes = null;
        try {
            byte[] in = data.getBytes("utf-8");
            arrayOfBytes = sm2Engine.processBlock(in, 0, in.length);
        } catch (Exception e) {
            log.error("SM2加密时出现异常:", e);
        }
        return Hex.toHexString(arrayOfBytes);
    }

    /**
     * SM2加密算法
     * @param publicKey     公钥
     * @param data          明文数据
     * @return
     */
    public static String encrypt(PublicKey publicKey, String data) {

        ECPublicKeyParameters ecPublicKeyParameters = null;
        if (publicKey instanceof BCECPublicKey) {
            BCECPublicKey bcecPublicKey = (BCECPublicKey) publicKey;
            ECParameterSpec ecParameterSpec = bcecPublicKey.getParameters();
            ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(),
                    ecParameterSpec.getG(), ecParameterSpec.getN());
            ecPublicKeyParameters = new ECPublicKeyParameters(bcecPublicKey.getQ(), ecDomainParameters);
        }

        SM2Engine sm2Engine = new SM2Engine();
        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) {
            log.error("SM2加密时出现异常:", e);
        }
        return Hex.toHexString(arrayOfBytes);
    }

    /**
     * SM2解密算法
     * @param privateKey    私钥
     * @param cipherData    密文数据
     * @return
     */
    public static String decrypt(String privateKey, String cipherData) {
        byte[] cipherDataByte = Hex.decode(cipherData);

        //获取一条SM2曲线参数
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
        //构造domain参数
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                sm2ECParameters.getG(), sm2ECParameters.getN());

        BigInteger privateKeyD = new BigInteger(privateKey, 16);
        ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);

        SM2Engine sm2Engine = new SM2Engine();
        sm2Engine.init(false, privateKeyParameters);

        String result = null;
        try {
            byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
            return new String(arrayOfBytes, "utf-8");
        } catch (Exception e) {
            log.error("SM2解密时出现异常:", e);
        }
        return result;

    }

    /**
     * SM2解密算法
     * @param privateKey        私钥
     * @param cipherData        密文数据
     * @return
     */
    public static String decrypt(PrivateKey privateKey, String cipherData) {
        byte[] cipherDataByte = Hex.decode(cipherData);

        BCECPrivateKey bcecPrivateKey = (BCECPrivateKey) privateKey;
        ECParameterSpec ecParameterSpec = bcecPrivateKey.getParameters();

        ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(),
                ecParameterSpec.getG(), ecParameterSpec.getN());

        ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(bcecPrivateKey.getD(),
                ecDomainParameters);

        SM2Engine sm2Engine = new SM2Engine();
        sm2Engine.init(false, ecPrivateKeyParameters);

        String result = null;
        try {
            byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
            return new String(arrayOfBytes, "utf-8");
        } catch (Exception e) {
            log.error("SM2解密时出现异常:", e);
        }
        return result;
    }

    /**
     * 将未压缩公钥压缩成压缩公钥
     * 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
     * @param pubKey    未压缩公钥(16进制,不要带头部04)
     * @return
     */
    public static String compressPubKey(String pubKey) {
        pubKey = "04" + pubKey;    //将未压缩公钥加上未压缩标识.
        // 获取一条SM2曲线参数
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
        //提取公钥点
        ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(pubKey));
        String compressPubKey = Hex.toHexString(pukPoint.getEncoded(Boolean.TRUE));

        return compressPubKey;
    }

    /**
     * 将压缩的公钥解压为非压缩公钥
     * @param compressKey   压缩公钥
     * @return
     */
    public static String unCompressPubKey(String compressKey) {
        // 获取一条SM2曲线参数
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
        //提取公钥点
        ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(compressKey));
        String pubKey = Hex.toHexString(pukPoint.getEncoded(Boolean.FALSE));
        //去掉前面的04   (04的时候,可以去掉前面的04)
        pubKey = pubKey.substring(2);
        return pubKey;
    }

    public static void main(String[] args) {
        SMKeyPair smKeyPair = genKeyPair(false);
        String priKey = smKeyPair.getPriKey();
        System.out.println("私钥"+ priKey);
        String pubKey = smKeyPair.getPubKey();
        System.out.println("公钥"+ pubKey);
        //公钥解压缩
        String substring = pubKey.substring(2, pubKey.length());
        String s = compressPubKey(substring);
        System.out.println("压缩后" + s);
        String s1 = unCompressPubKey(s);
        System.out.println("解压后" + s1);
        //明文
        String text = "123123123";
        System.out.println("测试明文文本" + text);
        //签名验签测试
        String sign = "";
        try {
            sign = sign(priKey, Hex.toHexString(text.getBytes()));
        } catch (CryptoException e) {
            e.printStackTrace();
        }
        System.out.println("生成签名" + sign);
        boolean verify = verify(pubKey, Hex.toHexString(text.getBytes()), sign);
        System.out.println("验签结果" + verify);

        //加解密测试
        String encryptData = encrypt(pubKey, text);
        System.out.println("加密结果" + encryptData);
        String decryptData = decrypt(priKey, encryptData);
        System.out.println("解密结果" + decryptData);
    }
}
package com.lxls.personalachievement.tools.smnew;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 1. @description: 钥匙对
 * 2. @author: xh
 * 3. @time: 2022/3/18
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SMKeyPair {
    //私钥
    private String priKey;
    //公钥
    private String pubKey;

}

到了这里,关于终于把前后端sm加解密以及加签验证调通了。的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 国密:SM2公私钥加签验签

    POM中增加hutool  工具类 加签逻辑中要用SM3计算摘要,对于工具类中的计算逻辑 在如图所示位置   工具类加签验签计算摘要逻辑一致,可以验签,若和第三方对接需要调整逻辑!!!

    2024年02月13日
    浏览(39)
  • RSA加密,解密,加签及验签

    目录 1.说明 2.加密和加签的区别 3.后端加密,解密,加签及验签示例 4.前端加密,解密,加签及验签示例 5.前端加密,后端解密,前端加签,后端验签 6.注意事项 1.说明 RSA算法是一种非对称加密算法,与对称加密算法不同的是,RSA算法有两个不同的密钥,一个是公钥,一个是私钥

    2024年02月20日
    浏览(61)
  • 国密算法SM2/3/4简单比较,以及基于Java的SM4(ECB模式,CBC模式)对称加解密实现

    常用的国密算法包含SM2,SM3,SM4。以下针对每个算法使用场景进行说明以比较其差异 SM2:非对称加密算法,可以替代RSA 数字签名,SM2为非对称加密,加解密使用一对私钥和公钥,只有签名发行者拥有私钥,可用于加密,其他需要验证解密或验签者使用公钥进行。如果使用公

    2024年04月13日
    浏览(41)
  • thinkphp6前后端验证码分离以及验证

    1.验证码接口生成验证码: 也可以自己写方法 2.验证方法和普通模式session验证有区别,需要改原文件:          修改后的代码:

    2024年02月12日
    浏览(42)
  • Java之SM4解密与解密

    在线加密工具链接  在线SM4国密加密/解密—LZL在线工具 在线SM4国密加密/解密 https://lzltool.cn/SM4 根据项目选择相应数据格式  pom.xml引入一下jar包 实现SM4加密和解密代码部分

    2024年02月06日
    浏览(33)
  • 【Java加解密系列】- SM4加解密

    之前文章介绍过SM2生成密钥和加解密的代码实现过程,这篇文章主要介绍下SM4对称加密算法的代码实现,依然还是引用的BC库。代码实现比较简单,直接上代码: 跑个测试用例试一下: 输出结果如下:

    2024年02月05日
    浏览(41)
  • 前端使用国密sm2和sm4进行加解密

    国密SM:国密算法,即国家商用密码算法。是由国家密码管理局认定和公布的密码算法标准及其应用规范,其中部分密码算法已经成为国际标准。如SM系列密码,SM代表商密,即商业密码,是指用于商业的、不涉及国家秘密的密码技术。 安装SM加密依赖 SM2 封装 将sm2的加密解密

    2024年02月08日
    浏览(60)
  • 【vue+sm2】前端使用国密sm2,加解密

    1.第一步就是安装依赖 2.导入sm2 3.先定义私钥或者公钥,私钥是解密,公钥是加密 4.设置加密模式 5.解密的使用全码 6.加密的实现全码

    2024年02月16日
    浏览(50)
  • 前端国密加解密使用方法SM2、SM3、SM4

       国密算法,即国家商用密码算法。是由国家密码管理局认定和公布的密码算法标准及其应用规范,其中部分密码算法已经成为国际标准。如SM系列密码,SM代表商密,即商业密码,是指用于商业的、不涉及国家秘密的密码技术。      不多废话直接上干货 项目中 可能存在

    2023年04月09日
    浏览(51)
  • SM2 加解密 一文理清

    1. 给一个私钥的der文件。   通过命令查看公私钥数据。 F:projectsimkeynowgmssl ec -inform der -in anca_ec_keypri.der -text Using configuration from C:Program FilesCommon FilesSSL/openssl.cnf read EC key Private-Key: (256 bit) priv:     90:8d:22:29:03:f2:8d:bf:45:20:ff:57:77:d4:a1:     cb:57:09:6b:99:45:51:62:bd:2b:d7:d3:60:b1:c

    2023年04月20日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包