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

相关文章

基于C++的UDP网络通信系统设计与实现详解

《基于C++的UDP网络通信系统设计与实现详解》在网络编程领域,UDP作为一种无连接的传输层协议,以其高效、低延迟的特性在实时性要求高的应用场景中占据重要地位,下面我们就来看看如何从零开始构建一个完整... 目录前言一、UDP服务器UdpServer.hpp1.1 基本框架设计1.2 初始化函数Init详解

Java中Map的五种遍历方式实现与对比

《Java中Map的五种遍历方式实现与对比》其实Map遍历藏着多种玩法,有的优雅简洁,有的性能拉满,今天咱们盘一盘这些进阶偏基础的遍历方式,告别重复又臃肿的代码,感兴趣的小伙伴可以了解下... 目录一、先搞懂:Map遍历的核心目标二、几种遍历方式的对比1. 传统EntrySet遍历(最通用)2. Lambd

Spring Boot 中 RestTemplate 的核心用法指南

《SpringBoot中RestTemplate的核心用法指南》本文详细介绍了RestTemplate的使用,包括基础用法、进阶配置技巧、实战案例以及最佳实践建议,通过一个腾讯地图路线规划的案... 目录一、环境准备二、基础用法全解析1. GET 请求的三种姿势2. POST 请求深度实践三、进阶配置技巧1

springboot+redis实现订单过期(超时取消)功能的方法详解

《springboot+redis实现订单过期(超时取消)功能的方法详解》在SpringBoot中使用Redis实现订单过期(超时取消)功能,有多种成熟方案,本文为大家整理了几个详细方法,文中的示例代... 目录一、Redis键过期回调方案(推荐)1. 配置Redis监听器2. 监听键过期事件3. Redi

Spring Boot 处理带文件表单的方式汇总

《SpringBoot处理带文件表单的方式汇总》本文详细介绍了六种处理文件上传的方式,包括@RequestParam、@RequestPart、@ModelAttribute、@ModelAttr... 目录方式 1:@RequestParam接收文件后端代码前端代码特点方式 2:@RequestPart接

SpringBoot整合Zuul全过程

《SpringBoot整合Zuul全过程》Zuul网关是微服务架构中的重要组件,具备统一入口、鉴权校验、动态路由等功能,它通过配置文件进行灵活的路由和过滤器设置,支持Hystrix进行容错处理,还提供... 目录Zuul网关的作用Zuul网关的应用1、网关访问方式2、网关依赖注入3、网关启动器4、网关全局变

SpringBoot全局异常拦截与自定义错误页面实现过程解读

《SpringBoot全局异常拦截与自定义错误页面实现过程解读》本文介绍了SpringBoot中全局异常拦截与自定义错误页面的实现方法,包括异常的分类、SpringBoot默认异常处理机制、全局异常拦... 目录一、引言二、Spring Boot异常处理基础2.1 异常的分类2.2 Spring Boot默

基于SpringBoot实现分布式锁的三种方法

《基于SpringBoot实现分布式锁的三种方法》这篇文章主要为大家详细介绍了基于SpringBoot实现分布式锁的三种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、基于Redis原生命令实现分布式锁1. 基础版Redis分布式锁2. 可重入锁实现二、使用Redisso

SpringBoo WebFlux+MongoDB实现非阻塞API过程

《SpringBooWebFlux+MongoDB实现非阻塞API过程》本文介绍了如何使用SpringBootWebFlux和MongoDB实现非阻塞API,通过响应式编程提高系统的吞吐量和响应性能... 目录一、引言二、响应式编程基础2.1 响应式编程概念2.2 响应式编程的优势2.3 响应式编程相关技术

SpringBoot的全局异常拦截实践过程

《SpringBoot的全局异常拦截实践过程》SpringBoot中使用@ControllerAdvice和@ExceptionHandler实现全局异常拦截,@RestControllerAdvic... 目录@RestControllerAdvice@ResponseStatus(...)@Except