当前位置: 首页 > article >正文

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 国密与国际密的对应关系

加密方式 国密 国际密
对称加密 SM1 AES(Advanced Encryption Standard)
非对称加密 SM2 RSA(Ron Rivest、Adi Shamir、Leonard Adleman)三人姓氏首字母拼在一起
摘要算法(杂凑) SM3 MD5(Message-Digest Algorithm)
SHA系列(Secure Hash Algorithm)
对称加密 SM4 DES(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;

    /**
     * 生成公钥和私钥
     */
    public static KeyPair generateSm2KeyPair() {
   
        //使用标准名称创建EC参数生成的参数规范
        final ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");

        // 获取一个椭圆曲线类型的密钥对生成器
        final KeyPairGenerator kpg;
        try {
   
            kpg = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
            // 使用SM2算法域参数集初始化密钥生成器(默认使用以最高优先级安装的提供者的 SecureRandom 的实现作为随机源)
            // kpg.initialize(sm2Spec);

            // 使用SM2的算法域参数集和指定的随机源初始化密钥生成器
            kpg.initialize(sm2Spec, new SecureRandom());

            // 通过密钥生成器生成密钥对
            return kpg.generateKeyPair();
        } catch (Exception e) {
   
            log.error(">>>>>>>>>>【ERROR】SM2密钥对生成失败,原因:{}", e.getMessage(), e);
            throw new RuntimeException("SM2密钥对生成失败");
        }
    }

    /**
     * 私钥转换为 {@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[] 

http://www.kler.cn/a/289831.html

相关文章:

  • 学Linux的第八天
  • 操作系统离散存储练习题
  • Rust 整数
  • 大数据 ETL + Flume 数据清洗 — 详细教程及实例(附常见问题及解决方案)
  • 微服务架构面试内容整理-SpringCloud Netflix‌与Spring Cloud Alibaba比较
  • 一文了解珈和科技在农业遥感领域的服务内容和能力
  • 【Qt】QChart折线图
  • ROS 编程入门
  • 集成电路学习:什么是IP知识产权
  • 本地搭建 Whisper 语音识别模型实现实时语音识别研究
  • 单线程Redis:Redis为什么这么快
  • 【html】编辑器、基础、属性、标题、段落、格式化、 连接、头部、CSS、图像
  • 微服务日常总结
  • 【主机入侵检测】Wazuh解码器之JSON解码器
  • 24并发设计模式——线程池模式
  • 台球助教系统小程序源码开发与技术解析
  • LLM大模型学习:LoRA 大模型微调的利器
  • 第三届人工智能与智能信息处理国际学术会议(AIIIP 2024)
  • 在SpringMVC中用fmt标签实现国际化/多语言
  • 装饰器模式(Decorator Pattern)
  • MACOS安装配置前端开发环境
  • 北芯生命持续亏损:产能利用率不理想仍扩产能,销售费用越来越高
  • Python世界:文件自动化备份实践
  • 由一个 SwiftData “诡异”运行时崩溃而引发的钩深索隐(一)
  • 工业交换机如何确保品质
  • glsl着色器学习(四)