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中JSON格式反序列化为Map且保证存取顺序一致的问题

《Java中JSON格式反序列化为Map且保证存取顺序一致的问题》:本文主要介绍Java中JSON格式反序列化为Map且保证存取顺序一致的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未... 目录背景问题解决方法总结背景做项目涉及两个微服务之间传数据时,需要提供方将Map类型的数据序列化为co

Java Lambda表达式的使用详解

《JavaLambda表达式的使用详解》:本文主要介绍JavaLambda表达式的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、前言二、Lambda表达式概述1. 什么是Lambda表达式?三、Lambda表达式的语法规则1. 无参数的Lambda表

java中Optional的核心用法和最佳实践

《java中Optional的核心用法和最佳实践》Java8中Optional用于处理可能为null的值,减少空指针异常,:本文主要介绍java中Optional核心用法和最佳实践的相关资料,文中... 目录前言1. 创建 Optional 对象1.1 常规创建方式2. 访问 Optional 中的值2.1

Spring Boot 整合 Apache Flink 的详细过程

《SpringBoot整合ApacheFlink的详细过程》ApacheFlink是一个高性能的分布式流处理框架,而SpringBoot提供了快速构建企业级应用的能力,下面给大家介绍Spri... 目录Spring Boot 整合 Apache Flink 教程一、背景与目标二、环境准备三、创建项目 & 添

Spring组件实例化扩展点之InstantiationAwareBeanPostProcessor使用场景解析

《Spring组件实例化扩展点之InstantiationAwareBeanPostProcessor使用场景解析》InstantiationAwareBeanPostProcessor是Spring... 目录一、什么是InstantiationAwareBeanPostProcessor?二、核心方法解

IDEA如何实现远程断点调试jar包

《IDEA如何实现远程断点调试jar包》:本文主要介绍IDEA如何实现远程断点调试jar包的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录问题步骤总结问题以jar包的形式运行Spring Boot项目时报错,但是在IDEA开发环境javascript下编译

深入解析 Java Future 类及代码示例

《深入解析JavaFuture类及代码示例》JavaFuture是java.util.concurrent包中用于表示异步计算结果的核心接口,下面给大家介绍JavaFuture类及实例代码,感兴... 目录一、Future 类概述二、核心工作机制代码示例执行流程2. 状态机模型3. 核心方法解析行为总结:三

Spring @RequestMapping 注解及使用技巧详解

《Spring@RequestMapping注解及使用技巧详解》@RequestMapping是SpringMVC中定义请求映射规则的核心注解,用于将HTTP请求映射到Controller处理方法... 目录一、核心作用二、关键参数说明三、快捷组合注解四、动态路径参数(@PathVariable)五、匹配请

Java -jar命令如何运行外部依赖JAR包

《Java-jar命令如何运行外部依赖JAR包》在Java应用部署中,java-jar命令是启动可执行JAR包的标准方式,但当应用需要依赖外部JAR文件时,直接使用java-jar会面临类加载困... 目录引言:外部依赖JAR的必要性一、问题本质:类加载机制的限制1. Java -jar的默认行为2. 类加

Java进程CPU使用率过高排查步骤详细讲解

《Java进程CPU使用率过高排查步骤详细讲解》:本文主要介绍Java进程CPU使用率过高排查的相关资料,针对Java进程CPU使用率高的问题,我们可以遵循以下步骤进行排查和优化,文中通过代码介绍... 目录前言一、初步定位问题1.1 确认进程状态1.2 确定Java进程ID1.3 快速生成线程堆栈二、分析