国密SM2算法进行数据的加密、签名和验签、解密

2024-02-08 17:20

本文主要是介绍国密SM2算法进行数据的加密、签名和验签、解密,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、背景介绍

数据的加解密有很多种方式,几种常用的加密算法如下:

DES(Data Encryption Standard):对称算法,数据加密标准,速度较快,适用于加密大量数据的场合;

3DES(Triple DES):是基于DES的对称算法,对一块数据用三个不同的密钥进行三次加密,强度更高;

RC2和RC4:对称算法,用变长密钥对大量数据进行加密,比 DES 快;

IDEA(International Data Encryption Algorithm)国际数据加密算法,使用 128 位密钥提供非常强的安全性;

RSA:由 RSA 公司发明,是一个支持变长密钥的公共密钥算法,需要加密的文件块的长度也是可变的,非对称算法

本文着重介绍SM2国密算法的使用,这是一款中国国家密码局发布的一款加密算法,本文介绍使用语言环境为java语言 

二、引入pom依赖

<dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><version>1.70</version>
</dependency>
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>provided</scope>
</dependency>

主要是引入了工具包和lombok依赖

 三、国密公私钥对工具类KeyUtils

package com.hl.sm2demo.util;import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jce.provider.BouncyCastleProvider;import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Map;/*** @ Description 国密公私钥对工具类*/
@Slf4j
public class KeyUtils {public static final String PUBLIC_KEY = "publicKey";public static final String PRIVATE_KEY = "privateKey";/*** 生成国密公私钥对*/public static Map<String, String> generateSmKey() throws Exception {KeyPairGenerator keyPairGenerator = null;SecureRandom secureRandom = new SecureRandom();ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");keyPairGenerator = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());keyPairGenerator.initialize(sm2Spec);keyPairGenerator.initialize(sm2Spec, secureRandom);KeyPair keyPair = keyPairGenerator.generateKeyPair();PrivateKey privateKey = keyPair.getPrivate();PublicKey publicKey = keyPair.getPublic();String publicKeyStr = new String(Base64.getEncoder().encode(publicKey.getEncoded()));String privateKeyStr = new String(Base64.getEncoder().encode(privateKey.getEncoded()));return Map.of(PUBLIC_KEY, publicKeyStr, PRIVATE_KEY, privateKeyStr);}/*** 将Base64转码的公钥串,转化为公钥对象*/public static PublicKey createPublicKey(String publicKey) {PublicKey publickey = null;try {X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey));KeyFactory keyFactory = KeyFactory.getInstance("EC", new BouncyCastleProvider());publickey = keyFactory.generatePublic(publicKeySpec);} catch (Exception e) {log.error("将Base64转码的公钥串,转化为公钥对象异常:{}", e.getMessage(), e);}return publickey;}/*** 将Base64转码的私钥串,转化为私钥对象*/public static PrivateKey createPrivateKey(String privateKey) {PrivateKey publickey = null;try {PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey));KeyFactory keyFactory = KeyFactory.getInstance("EC", new BouncyCastleProvider());publickey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);} catch (Exception e) {log.error("将Base64转码的私钥串,转化为私钥对象异常:{}", e.getMessage(), e);}return publickey;}}

生成公私钥字符串map对象,公钥串转公钥对象方法和私钥串转私钥对象方法 

四、 SM2工具类

package com.hl.sm2demo.util;import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
import org.bouncycastle.crypto.InvalidCipherTextException;
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 java.security.*;/*** @ Description SM2实现工具类*/
@Slf4j
public class Sm2Util {
/*    这行代码是在Java中用于向安全系统添加Bouncy Castle安全提供器的。Bouncy Castle是一个流行的开源加密库,它提供了许多密码学算法和安全协议的实现。通过调用Security.addProvider并传入BouncyCastleProvider对象,你可以注册Bouncy Castle提供的安全服务和算法到Java的安全框架中。这样一来,你就可以在你的应用程序中使用Bouncy Castle所提供的加密算法、密钥生成和管理等功能。*/static {Security.addProvider(new BouncyCastleProvider());}/*** 根据publicKey对原始数据data,使用SM2加密*/public static byte[] encrypt(byte[] data, PublicKey publicKey) {ECPublicKeyParameters localECPublicKeyParameters = getEcPublicKeyParameters(publicKey);SM2Engine localSM2Engine = new SM2Engine();localSM2Engine.init(true, new ParametersWithRandom(localECPublicKeyParameters, new SecureRandom()));byte[] arrayOfByte2;try {arrayOfByte2 = localSM2Engine.processBlock(data, 0, data.length);return arrayOfByte2;} catch (InvalidCipherTextException e) {log.error("SM2加密失败:{}", e.getMessage(), e);return null;}}private static ECPublicKeyParameters getEcPublicKeyParameters(PublicKey publicKey) {ECPublicKeyParameters localECPublicKeyParameters = null;if (publicKey instanceof BCECPublicKey localECPublicKey) {ECParameterSpec localECParameterSpec = localECPublicKey.getParameters();ECDomainParameters localECDomainParameters = new ECDomainParameters(localECParameterSpec.getCurve(),localECParameterSpec.getG(), localECParameterSpec.getN());localECPublicKeyParameters = new ECPublicKeyParameters(localECPublicKey.getQ(), localECDomainParameters);}return localECPublicKeyParameters;}/*** 根据privateKey对加密数据encode data,使用SM2解密*/public static byte[] decrypt(byte[] encodeData, PrivateKey privateKey) {SM2Engine localSM2Engine = new SM2Engine();BCECPrivateKey sm2PriK = (BCECPrivateKey) privateKey;ECParameterSpec localECParameterSpec = sm2PriK.getParameters();ECDomainParameters localECDomainParameters = new ECDomainParameters(localECParameterSpec.getCurve(),localECParameterSpec.getG(), localECParameterSpec.getN());ECPrivateKeyParameters localECPrivateKeyParameters = new ECPrivateKeyParameters(sm2PriK.getD(),localECDomainParameters);localSM2Engine.init(false, localECPrivateKeyParameters);try {return localSM2Engine.processBlock(encodeData, 0, encodeData.length);} catch (InvalidCipherTextException e) {log.error("SM2解密失败:{}", e.getMessage(), e);return null;}}/*** 私钥签名*/public static byte[] signByPrivateKey(byte[] data, PrivateKey privateKey) throws Exception {Signature sig = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString(), BouncyCastleProvider.PROVIDER_NAME);sig.initSign(privateKey);sig.update(data);return sig.sign();}/*** 公钥验签*/public static boolean verifyByPublicKey(byte[] data, PublicKey publicKey, byte[] signature) throws Exception {Signature sig = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString(), BouncyCastleProvider.PROVIDER_NAME);sig.initVerify(publicKey);sig.update(data);return sig.verify(signature);}}

五、案例测试Junit 

package com.hl.sm2demo;import com.hl.sm2demo.util.KeyUtils;
import com.hl.sm2demo.util.Sm2Util;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;
import java.util.Map;@SpringBootTest
class Sm2DemoApplicationTests {PublicKey publicKey = null;PrivateKey privateKey = null;@Testpublic void test() throws Exception {//生成公私钥对Map<String,String> keys = KeyUtils.generateSmKey();String testStr = "hello JAVA";System.out.println("原始字符串:" + testStr);System.out.println("公钥:" + keys.get(KeyUtils.PUBLIC_KEY));publicKey = KeyUtils.createPublicKey(keys.get(KeyUtils.PUBLIC_KEY));System.out.println("私钥:" + keys.get(KeyUtils.PRIVATE_KEY));privateKey = KeyUtils.createPrivateKey(keys.get(KeyUtils.PRIVATE_KEY));System.out.println();//公钥加密byte[] encrypt = Sm2Util.encrypt(testStr.getBytes(), publicKey);//加密转base64String encryptBase64Str = Base64.getEncoder().encodeToString(encrypt);System.out.println("加密数据:" + encryptBase64Str);//私钥签名,方便对方收到数据后用公钥验签byte[] sign = Sm2Util.signByPrivateKey(testStr.getBytes(), privateKey);System.out.println("数据签名:" + Base64.getEncoder().encodeToString(sign));//公钥验签,验证通过后再进行数据解密boolean b = Sm2Util.verifyByPublicKey(testStr.getBytes(), publicKey, sign);System.out.println("数据验签:" + b);//私钥解密byte[] decode = Base64.getDecoder().decode(encryptBase64Str);byte[] decrypt = Sm2Util.decrypt(decode, privateKey);assert decrypt != null;System.out.println("解密数据:" + new String(decrypt));}
}

测试代码主要逻辑:

密钥准备:首先生成一个公私钥对字符串,再使用工具分别转换为公私钥的java对象;

加密过程:把数据使用公钥加密,把密文转换成base64编码格式,再用私钥签名;

解密过程:拿到加密数据后用公钥验签,以确保密文数据没有被第三方拦截篡改,验证通过后,base64解码,最后使用私钥进行解密,还原数据

测试结果如下图:

这篇关于国密SM2算法进行数据的加密、签名和验签、解密的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/691697

相关文章

Pandas使用AdaBoost进行分类的实现

《Pandas使用AdaBoost进行分类的实现》Pandas和AdaBoost分类算法,可以高效地进行数据预处理和分类任务,本文主要介绍了Pandas使用AdaBoost进行分类的实现,具有一定的参... 目录什么是 AdaBoost?使用 AdaBoost 的步骤安装必要的库步骤一:数据准备步骤二:模型

Pandas统计每行数据中的空值的方法示例

《Pandas统计每行数据中的空值的方法示例》处理缺失数据(NaN值)是一个非常常见的问题,本文主要介绍了Pandas统计每行数据中的空值的方法示例,具有一定的参考价值,感兴趣的可以了解一下... 目录什么是空值?为什么要统计空值?准备工作创建示例数据统计每行空值数量进一步分析www.chinasem.cn处

使用Pandas进行均值填充的实现

《使用Pandas进行均值填充的实现》缺失数据(NaN值)是一个常见的问题,我们可以通过多种方法来处理缺失数据,其中一种常用的方法是均值填充,本文主要介绍了使用Pandas进行均值填充的实现,感兴趣的... 目录什么是均值填充?为什么选择均值填充?均值填充的步骤实际代码示例总结在数据分析和处理过程中,缺失数

如何使用 Python 读取 Excel 数据

《如何使用Python读取Excel数据》:本文主要介绍使用Python读取Excel数据的详细教程,通过pandas和openpyxl,你可以轻松读取Excel文件,并进行各种数据处理操... 目录使用 python 读取 Excel 数据的详细教程1. 安装必要的依赖2. 读取 Excel 文件3. 读

Spring 请求之传递 JSON 数据的操作方法

《Spring请求之传递JSON数据的操作方法》JSON就是一种数据格式,有自己的格式和语法,使用文本表示一个对象或数组的信息,因此JSON本质是字符串,主要负责在不同的语言中数据传递和交换,这... 目录jsON 概念JSON 语法JSON 的语法JSON 的两种结构JSON 字符串和 Java 对象互转

C++如何通过Qt反射机制实现数据类序列化

《C++如何通过Qt反射机制实现数据类序列化》在C++工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作,所以本文就来聊聊C++如何通过Qt反射机制实现数据类序列化吧... 目录设计预期设计思路代码实现使用方法在 C++ 工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作。由于数据类

SpringBoot使用GZIP压缩反回数据问题

《SpringBoot使用GZIP压缩反回数据问题》:本文主要介绍SpringBoot使用GZIP压缩反回数据问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录SpringBoot使用GZIP压缩反回数据1、初识gzip2、gzip是什么,可以干什么?3、Spr

QT进行CSV文件初始化与读写操作

《QT进行CSV文件初始化与读写操作》这篇文章主要为大家详细介绍了在QT环境中如何进行CSV文件的初始化、写入和读取操作,本文为大家整理了相关的操作的多种方法,希望对大家有所帮助... 目录前言一、CSV文件初始化二、CSV写入三、CSV读取四、QT 逐行读取csv文件五、Qt如何将数据保存成CSV文件前言

SpringBoot集成Milvus实现数据增删改查功能

《SpringBoot集成Milvus实现数据增删改查功能》milvus支持的语言比较多,支持python,Java,Go,node等开发语言,本文主要介绍如何使用Java语言,采用springboo... 目录1、Milvus基本概念2、添加maven依赖3、配置yml文件4、创建MilvusClient

SpringValidation数据校验之约束注解与分组校验方式

《SpringValidation数据校验之约束注解与分组校验方式》本文将深入探讨SpringValidation的核心功能,帮助开发者掌握约束注解的使用技巧和分组校验的高级应用,从而构建更加健壮和可... 目录引言一、Spring Validation基础架构1.1 jsR-380标准与Spring整合1