Java实现加密(六)国密SM2算法

2024-09-04 06:12

本文主要是介绍Java实现加密(六)国密SM2算法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

    • 一、SM2 简介
      • 1.1 概述
      • 1.2 国密与国际密的对应关系
      • 1.3 优势
      • 1.4 ECC加密算法 vs RSA加密算法
    • 二、SM2 应用场景
      • 2.1 数据加密
      • 2.2 密钥协商
      • 2.3 数字签名
    • 三、Java 实现 SM2 的两种方式
      • 3.1 Maven 依赖
      • 3.2 实现方式一
        • 1)SM2Utils.java
        • 2)SignatureSM2Util.java
        • 3)Param.java
        • 4)测试示例
        • 5)测试结果
      • 3.3 实现方式二
        • 1)SM2Utils.java
        • 2)SM2KeyPair.java
        • 3)测试示例
        • 4)测试结果
      • 3.4 两种实现方式比较
        • 第一种实现方式:
        • 第二种实现方式:
        • 比较:

一、SM2 简介

1.1 概述

SM2 算法是基于 ECC(Elliptic Curve Cryptography)椭圆曲线密码非对称加密 算法,其密钥长度为 256bit。该算法由 国家密码管理局 于 2010年12月17号发布

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

国密算法包括:SM1(SCB2)、SM2、SM3、SM4、SM7、SM9,以及 ZUC(祖冲之密码)等。

其中:

  • 1) SM1、SM4、SM7、ZUC(祖冲之密码)属于 对称算法
  • 2) SM2、SM9 属于 非对称算法
  • 3) SM3 属于 杂凑算法

1.2 国密与国际密的对应关系

加密方式国密国际密
对称加密SM1AES(Advanced Encryption Standard)
非对称加密SM2RSA(Ron Rivest、Adi Shamir、Leonard Adleman)三人姓氏首字母拼在一起
摘要算法(杂凑)SM3MD5(Message-Digest Algorithm)
SHA系列(Secure Hash Algorithm)
对称加密SM4DES(Data Encryption Standard)

1.3 优势

SM2 算法作为一种自主创新的密码算法,具有以下优势:

  1. 安全性高: 基于 椭圆曲线离散对数难题,安全性比较高,能够有效地防止黑客攻击。
  2. 效率高: 具有较高地运算效率,能够满足大量数据加密、解密和数字签名的需求。
  3. 灵活性好: 支持多种密钥长度,可根据实际需求灵活选择密钥长度,适用于不同的应用场景。
  4. 自主创新: SM2算法是我国自主创新的密码算法,具有独立的只是产权,能够保障国家关键信息系统的信息安全。

1.4 ECC加密算法 vs RSA加密算法

SM2算法 是基于 ECC 椭圆曲线算法 实现的,采用 256位 密钥长度,它的安全强度相对较高,在工程应用中难以实现,破译或求解难度基本上是指数级的。因此,SM2 算法可以用较少的计算能力提供比 RSA算法 更高的安全强度,而所需的密钥长度却远比 RSA算法低。

对比项目ECC加密算法RSA加密算法
密钥长度246位2048位
CPU占用较少较高
内存占用较少较高
网络小号较低较高
加密效率较高一般
破解难度具有数据特性,破解难度大相对ECC理论上容易些
抗攻击性一般
可扩展性一般
兼容范围支持新版浏览器和操作系统,单存在少数不支持平台,例如:cPanel广泛支持

二、SM2 应用场景

2.1 数据加密

  • 在非对称加密算法中,可对外公布的密钥称为 公钥,只有持有者所知的密钥称为 私钥。发送者使用接收者的公钥来加密信息,接收者用自己的私钥解密和读取该信息。

使用 SM2 非对称加密算法加解密数据的过程:

2.2 密钥协商

利用 SM2 算法进行密钥协商的过程:

  • 1) 会话双方生成自己的私钥(随机数);

  • 2) 会话双方由私钥、ECC椭圆曲线参数 G 各自计算出公钥;

  • 3) 会话双方将自己的公钥传递给对方,传递过程公开;

    (由于椭圆曲线的计算复杂性高,破解难度大,因此攻击者难以通过公钥和椭圆曲线参数 G 反推出私钥)

  • 4) 双方将自己的 私钥 与对方的 公钥 进行运算,最终得到相同的会话密钥,该会话密钥可作为共享密钥用于对称加密(例如:SM4算法)通信。

2.3 数字签名

数字签名 是一种用于 验证信息完整性、真实性和来源的技术手段。它通常用于确保数据在传输或存储过程中没有被篡改,并且可以追溯到特定的发送方。

  • 发送方使用 自己的私钥 对信息进行 加密,生成数字签名。
  • 接收方使用 发送方的公钥 对签名进行 解密验证,以验证消息的完整性和真实性。

三、Java 实现 SM2 的两种方式

3.1 Maven 依赖

bouncycastle - 1.57 版本之后,加入了对我国的 SM2、SM3、SM4算法的支持

<!-- SM2加密 -->
<dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><version>1.64</version>
</dependency>

3.2 实现方式一

1)SM2Utils.java
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.*;/*** 国密SM2算法工具类**/
@Slf4j
public class SM2Utils {private static final Charset CHARSETS = StandardCharsets.UTF_8;private static final SM2Engine.Mode DIGEST = SM2Engine.Mode.C1C3C2;/*** 私钥转换为 {@link ECPrivateKeyParameters}** @param key key* @return* @throws InvalidKeyException*/public static ECPrivateKeyParameters privateKeyToParams(byte[] key) throws InvalidKeyException, InvalidKeySpecException, NoSuchAlgorithmException {if (key == null) {throw new RuntimeException("key must be not null !");}PrivateKey privateKey = generatePrivateKey(key);return (ECPrivateKeyParameters) ECUtil.generatePrivateKeyParameter(privateKey);}/*** 生成私钥** @param key key* @return*/public static PrivateKey generatePrivateKey(byte[] key) throws NoSuchAlgorithmException, InvalidKeySpecException {if (key == null) {throw new RuntimeException("key must be not null !");}KeySpec keySpec = new PKCS8EncodedKeySpec(key);return getKeyFactory().generatePrivate(keySpec);}/*** 公钥转换为 {@link ECPublicKeyParameters}** @param key key* @return* @throws InvalidKeyException*/public static ECPublicKeyParameters publicKeyToParams(byte[] key) throws InvalidKeyException, InvalidKeySpecException, NoSuchAlgorithmException {if (key == null) {throw new RuntimeException("key must be not null !");}// 生成公钥KeySpec keySpec = new X509EncodedKeySpec(key);PublicKey publicKey = getKeyFactory().generatePublic(keySpec);return (ECPublicKeyParameters) ECUtil.generatePublicKeyParameter(publicKey);}/*** 获取{@link KeyFactory}** @return {@link KeyFactory}*/private static KeyFactory getKeyFactory() throws NoSuchAlgorithmException {final Provider provider = new BouncyCastleProvider();return KeyFactory.getInstance("EC", provider);}/*** 加密** @param dataStr   数据* @param publicKey 公钥* @return 加密之后的数据*/public static String encrypt(String dataStr, String publicKey) {try {return Base64.toBase64String(encrypt(dataStr.getBytes(StandardCharsets.UTF_8), Base64.decode(publicKey)));} catch (Exception e) {throw new RuntimeException("参数加密异常");}}public static byte[] encrypt(byte[] data, byte[] publicKey) throws Exception {CipherParameters pubKeyParameters = new ParametersWithRandom(publicKeyToParams(publicKey));SM2Engine engine = new SM2Engine(DIGEST);engine.init(true, pubKeyParameters);return engine.processBlock(data, 0, data.length);}/*** 解密** @param base64Data       数据* @param base64PrivateKey 私钥* @return 解密之后的数据*/public static String decrypt(String base64Data, String base64PrivateKey) throws Exception {byte[] data = Base64.decode(base64Data);byte[] privateKey = Base64.decode(base64PrivateKey);return new String(decrypt(data, privateKey), CHARSETS);}public static byte[] decrypt(byte[] data, byte[] privateKey) throws Exception {CipherParameters privateKeyParameters = privateKeyToParams(privateKey);SM2Engine engine = new SM2Engine(DIGEST);engine.init(false, privateKeyParameters);return engine.processBlock(data, 0, data.length);}/*** 签名** @param data 数据* @return 签名*/public static byte[] sign(byte[] data, byte[] privateKey) throws Exception {SM2Signer signer = new SM2Signer();CipherParameters param = new ParametersWithRandom(privateKeyToParams(privateKey));signer.init(true, param);signer.update(data, 0, data.length);return signer.generateSignature();}/*** 用公钥检验数字签名的合法性** @param data      数据* @param sign      签名* @param publicKey 公钥* @return 是否验证通过*/public static boolean verify(byte[] data, byte[] sign, byte[] publicKey) throws Exception {SM2Signer signer = new SM2Signer();CipherParameters param = publicKeyToParams

这篇关于Java实现加密(六)国密SM2算法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

Spring AI集成DeepSeek的详细步骤

《SpringAI集成DeepSeek的详细步骤》DeepSeek作为一款卓越的国产AI模型,越来越多的公司考虑在自己的应用中集成,对于Java应用来说,我们可以借助SpringAI集成DeepSe... 目录DeepSeek 介绍Spring AI 是什么?1、环境准备2、构建项目2.1、pom依赖2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

Spring Cloud LoadBalancer 负载均衡详解

《SpringCloudLoadBalancer负载均衡详解》本文介绍了如何在SpringCloud中使用SpringCloudLoadBalancer实现客户端负载均衡,并详细讲解了轮询策略和... 目录1. 在 idea 上运行多个服务2. 问题引入3. 负载均衡4. Spring Cloud Load

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

在 Spring Boot 中使用 @Autowired和 @Bean注解的示例详解

《在SpringBoot中使用@Autowired和@Bean注解的示例详解》本文通过一个示例演示了如何在SpringBoot中使用@Autowired和@Bean注解进行依赖注入和Bean... 目录在 Spring Boot 中使用 @Autowired 和 @Bean 注解示例背景1. 定义 Stud

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque