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

6.开源非对称加密算法SM2实现

6.开源非对称加密算法SM2实现

前期内容导读:

  1. 开源加解密RSA/AES/SHA1/PGP/SM2/SM3/SM4介绍
  2. 开源AES/SM4/3DES对称加密算法介绍及其实现
  3. 开源AES/SM4/3DES对称加密算法的验证实现
  4. 开源非对称加密算法RSA/SM2实现及其应用
  5. 开源非对称加密算法RSA实现

1. 开源组件 非对称秘钥加密介绍

  • 加密组件引入方法:
    <dependency><groupId>com.biuqu</groupId><artifactId>bq-encryptor</artifactId><version>1.0.1</version>
    </dependency>
    

1.1 SM2的加解密实现

  • 加解密核心逻辑
    public byte[] doCipher(byte[] data, byte[] key, int cipherMode)
    {SM2Engine.Mode mode = SM2Engine.Mode.C1C2C3;if (!this.getPaddingMode().equalsIgnoreCase(String.valueOf(DEFAULT_MODE))){mode = SM2Engine.Mode.C1C3C2;}SM2Engine sm2Engine = new SM2Engine(mode);this.initSm2Engine(sm2Engine, key, cipherMode);try{return sm2Engine.processBlock(data, 0, data.length);}catch (Exception e){throw new EncryptionException("failed to do sm2 cipher.", e);}
    }private void initSm2Engine(SM2Engine sm2Engine, byte[] key, int cipherMode)
    {if (Cipher.ENCRYPT_MODE == cipherMode){ECPublicKey keyObj = (ECPublicKey)this.toPubKey(key);ECDomainParameters domainParam = this.getDomainParam(keyObj);ECKeyParameters keyParam = new ECPublicKeyParameters(keyObj.getQ(), domainParam);byte[] initKey = UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8);sm2Engine.init(true, new ParametersWithRandom(keyParam, this.createRandom(initKey)));}else{ECPrivateKey keyObj = (ECPrivateKey)this.toPriKey(key);ECDomainParameters domainParam = this.getDomainParam(keyObj);ECKeyParameters keyParam = new ECPrivateKeyParameters(keyObj.getD(), domainParam);sm2Engine.init(false, keyParam);}
    }  
    

    说明:

    1. 上面的代码阐述了加解密的核心流程:根据二进制生成秘钥,再基于单独的API计算得到加解密结果,该计算逻辑完全不同于以往的加解密API;
    2. 通过上述核心代码逻辑,再对比上篇5.非对称加密算法RSA实现,可知SM2本身是支持分段的;
    3. 通过秘钥二进制反向生成秘钥对象是一个有意思且有点复杂的事情,后面再单独说明;

1.2 SM2生成秘钥及转换实现

  • 秘钥生成逻辑

    public KeyPair createKey(byte[] initKey)
    {try{ECGenParameterSpec paramSpec = new ECGenParameterSpec(SM2_VERSION);KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM, this.getProvider());if (null == initKey){initKey = UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8);}SecureRandom random = this.createRandom(initKey);keyGen.initialize(paramSpec, random);return keyGen.generateKeyPair();}catch (Exception e){throw new EncryptionException("failed to get sm2 key.", e);}
    }
    
  • 公钥、私钥反向生成逻辑

    public PublicKey toPubKey(byte[] pubKey)
    {try{String hexKey = Hex.toHexString(pubKey);KeyFactory kf = KeyFactory.getInstance(ALGORITHM, this.getProvider());if (hexKey.startsWith(STANDARD_HEX_KEY_PREFIX)){return kf.generatePublic(new X509EncodedKeySpec(pubKey));}else{// 获取SM2相关参数X9ECParameters ecParam = GMNamedCurves.getByName(SM2_VERSION);// 将公钥HEX字符串转换为椭圆曲线对应的点ECCurve ecCurve = ecParam.getCurve();ECPoint ecPoint = ecCurve.decodePoint(pubKey);// 椭圆曲线参数规格ECParameterSpec ecSpec = new ECParameterSpec(ecCurve, ecParam.getG(), ecParam.getN(), ecParam.getH());// 将椭圆曲线点转为公钥KEY对象return kf.generatePublic(new ECPublicKeySpec(ecPoint, ecSpec));}}catch (Exception e){throw new EncryptionException("failed to get sm2 pub key.", e);}
    }public PrivateKey toPriKey(byte[] priKey)
    {try{String hexKey = Hex.toHexString(priKey);KeyFactory kf = KeyFactory.getInstance(ALGORITHM, this.getProvider());if (hexKey.startsWith(STANDARD_HEX_KEY_PREFIX)){PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(priKey);return kf.generatePrivate(keySpec);}else{// 获取SM2相关参数X9ECParameters ecParam = GMNamedCurves.getByName(SM2_VERSION);ECCurve ecCurve = ecParam.getCurve();// 椭圆曲线参数规格ECParameterSpec ecSpec = new ECParameterSpec(ecCurve, ecParam.getG(), ecParam.getN(), ecParam.getH());// 将私钥HEX字符串转换为16进制的数字值BigInteger bigInteger = new BigInteger(Hex.toHexString(priKey), EncryptionConst.HEX_UNIT);// 将X值转为私钥KEY对象return kf.generatePrivate(new ECPrivateKeySpec(bigInteger, ecSpec));}}catch (Exception e){throw new EncryptionException("failed to get sm2 pri key.", e);}
    }
    

    说明:SM2基于椭圆的原理来加解密,其秘钥生成和解析方式也与其它方式不同。

    1. SM2支持标准的秘钥生成方式:
    BaseSingleSignature sm2 = new Sm2Encryption();
    KeyPair keyPair = sm2.createKey(UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8));
    byte[] priKey0 = keyPair.getPrivate().getEncoded();
    byte[] pubKey0 = keyPair.getPublic().getEncoded();
    
    1. SM2支持非标准的秘钥生成方式:
    BaseSingleSignature sm2 = new Sm2Encryption();
    KeyPair keyPair = sm2.createKey(UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8));
    byte[] priKey1 = ((BCECPrivateKey)keyPair.getPrivate()).getD().toByteArray();
    byte[] pubKey1 = ((BCECPublicKey)keyPair.getPublic()).getQ().getEncoded(false);
    byte[] pubKey2 = ((BCECPublicKey)keyPair.getPublic()).getQ().getEncoded(true);
    
    1. 上述正文部分的秘钥转换逻辑可以无感兼容上述各种秘钥场景。有兴趣可以看看此算法的单元测试类。PS:网上资料通常只描述了其中一种秘钥生成场景,但是相互间是不兼容的。
  • 签名和验签判定逻辑:

    public byte[] sign(byte[] data, byte[] key)
    {try{PrivateKey priKey = this.toPriKey(key);Signature signature = Signature.getInstance(this.getSignatureAlg(), this.getProvider());signature.initSign(priKey);signature.update(data);return signature.sign();}catch (Exception e){throw new EncryptionException("failed to signature.", e);}
    }public boolean verify(byte[] data, byte[] key, byte[] sign)
    {try{PublicKey pubKey = this.toPubKey(key);Signature signature = Signature.getInstance(this.getSignatureAlg(), this.getProvider());signature.initVerify(pubKey);signature.update(data);return signature.verify(sign);}catch (Exception e){throw new EncryptionException("failed to verify signature.", e);}
    }
    
  • SM2加密批量验证逻辑

    @Test
    public void encrypt()
    {int[] encLengths = {256};super.encrypt(encLengths);
    }@Test
    public void testEncryptAndSign()
    {String initKey = UUID.randomUUID() + new String(RandomUtils.nextBytes(5000), StandardCharsets.UTF_8);int[] encLengths = {256};BaseSingleSignature encryption = new Sm2Encryption();for (int encLen : encLengths){encryption.setEncryptLen(encLen);KeyPair keyPair = encryption.createKey(initKey.getBytes(StandardCharsets.UTF_8));super.testEncryptAndSign(encryption, keyPair.getPrivate().getEncoded(), keyPair.getPublic().getEncoded());}
    }  
    

    说明:

    1. SM2可以不用设置加密长度,因为默认只有一个,同理我们也无需关心其填充算法;
    2. 通过单元测试对比RSA算法可知,SM2由于秘钥非常短,其秘钥生成和加解密效率明显高于RSA;

2. 总结:

  1. 基于BouncyCastleSM2由于其算法独特性,与其它的算法实现差异加大,但是在实际使用时,由于其秘钥非常短,在核心的加解密执行效率上是有一定优势的;
  2. SM2支持多种方式的秘钥生成,本开源组件较好地解决了秘钥不同方式生成的兼容问题;
  3. SM2算法相对来说还比较新,在有些秘改(国密改造)场景时,还无法做到。因为大部分开源组件只支持标准协议,一般支持p256v1非对称加密,但是不支持sm2p256v1,国人仍需努力。

相关文章:

6.开源非对称加密算法SM2实现

6.开源非对称加密算法SM2实现 前期内容导读&#xff1a; 开源加解密RSA/AES/SHA1/PGP/SM2/SM3/SM4介绍开源AES/SM4/3DES对称加密算法介绍及其实现开源AES/SM4/3DES对称加密算法的验证实现开源非对称加密算法RSA/SM2实现及其应用开源非对称加密算法RSA实现 1. 开源组件 非对称秘…...

Toolformer and Tool Learning(LLMs如何使用工具)

大模型的能力让学术和工业界都对通用人工智能的未来充满幻想&#xff0c;在前一篇博文中已经粗略介绍&#xff0c; Augmented Language Models&#xff08;增强语言模型&#xff09; ALM的两大思路是推理和工具&#xff0c;本篇博文整理两篇关于Toolformer或Tool Learning的论…...

029:Mapbox GL绘制铁路黑白交替的线段

第029个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+mapbox中加载数据显示铁路标识的那种黑白交替的线段。 直接复制下面的 vue+mapbox源代码,操作2分钟即可运行实现效果 文章目录 示例效果配置方式示例源代码(共94行)相关API参考:专栏目标示例效果 配置方式 1)…...

结对编程 --- 大部分程序员喜欢的编程方式

一、介绍 结对编程起源时间可以追溯到 1990 年代早期。这种编程方法最初由 Jim Highsmith 和 Alistair Cockburn 等人提出。后来&#xff0c;Kent Beck 和 Ward Cunningham 等人将其发展成为一种敏捷开发方法&#xff0c;被称为“极限编程”&#xff08;Extreme Programming&am…...

kubernetes-informer机制

一、概念 informer 是 client-go 中的核心工具包&#xff0c;在kubernetes中&#xff0c;各个组件通过HTTP协议跟 API Server 进行通信。如果各组件每次都直接和API Server 进行交互&#xff0c;会给API Server 和ETCD造成非常大的压力。在不依赖任何中间件的情况下&#xff0…...

LeetCode 2451. Odd String Difference【字符串,哈希表】简单

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…...

切片工具tippecanoe的全网最详细的解释

1.下载和安装 tippecanoe工具是mapbox官方提供的一个服务端切片工具,因此它是运行在服务器上的,它比较友好的支持mac和linux机器。对于windows来讲,就比较麻烦了。 首先对于mac系统,你只需配置好自己的homebrew,保证homebrew能够正常下载东西。 然后只需要一个命令: …...

Linux系统初始化命令的备忘单,Linux运维工程师收藏!

在管理和维护Linux系统时&#xff0c;有一些常用的命令可以帮助您进行系统初始化和配置。这些命令涵盖了各种任务&#xff0c;包括系统设置、用户管理、软件安装和网络配置等。 本文将为您提供一个Linux系统初始化命令的备忘单&#xff0c;以便在需要时方便查阅和使用。 系统设…...

五月最近一次面试,被阿里P8测开虐惨了...

都说金三银四涨薪季&#xff0c;我是着急忙慌的准备简历——5年软件测试经验&#xff0c;可独立测试大型产品项目&#xff0c;熟悉项目测试流程...薪资要求&#xff1f;5年测试经验起码能要个20K吧 我加班肝了一页半简历&#xff0c;投出去一周&#xff0c;面试电话倒是不少&a…...

工业机器视觉缺陷检测工作小结

工业机器视觉检测工作小结 &#xff08;因为网上没有很系统的讲义和文档&#xff0c;都是零零散散的&#xff0c;因此&#xff0c;我自己尝试着总结一下、仅供参考&#xff09; 你想知道的大概率在这都可以找到、相机的了解镜头的了解光源的了解传统算法DL深度学习方法 &#…...

技术笔记:默默耕耘,赢得铁粉的秘密策略!

目录 第一步&#xff1a;真实实践&#xff0c;价值分享第二步&#xff1a;高质量文章的撰写第三步&#xff1a;积极互动&#xff0c;回复评论和留言第四步&#xff1a;定期更新和持续学习第五步&#xff1a;参与技术社区第六步&#xff1a;社区问答和问题解答总结 导语&#xf…...

回收站中怎么找回误删除的文件?这几种方法很实用

当我们在电脑上操作文件的时候&#xff0c;难免会有不小心删除文件的情况发生。这个时候&#xff0c;我们可以打开回收站来找回误删除的文件。但是&#xff0c;有时候我们也会误将回收站清空。那么&#xff0c;该怎样才能找回已经误删除的文件呢&#xff1f;在这里提供了回收站…...

Gateway网关参数进行验签POST 包含requestbody 请求体封装

Gateway网关自定义拦截器的不可重复读取数据 特别注意一点, 因为在网关层 拿出 request 流之后,必须重写getbody()方法把所有的参数放进去,否则后面转发的请求无法接收到任何数据, 坑,巨坑,因为版本问题网上很多都不能兼容, 我的springboot环境 依赖包 <parent><gr…...

【Netty】字节缓冲区 ByteBuf (六)(上)

文章目录 前言一、ByteBuf类二、ByteBuffer 实现原理2.1 ByteBuffer 写入模式2.2 ByteBuffer 读取模式2.3 ByteBuffer 写入模式切换为读取模式2.4 clear() 与 compact() 方法2.5 ByteBuffer 使用案例 总结 前言 回顾Netty系列文章&#xff1a; Netty 概述&#xff08;一&…...

Python - 面向对象编程 - 实例方法、静态方法、类方法

实例方法 在类中定义的方法默认都是实例方法&#xff0c;前面几篇文章已经大量使用到实例方法 实例方法栗子 class PoloBlog:def __init__(self, name, age):print("自动调用构造方法")self.name nameself.age agedef test(self):print("一个实例方法&…...

性能测试——基本性能监控系统使用

这里写目录标题 一、基本性能监控系统组成二、环境搭建1、准备数据文件 type.db collectd.conf2、启动InfluxDB3、启动grafana4、启动collectd5、Grafana中配置数据源 一、基本性能监控系统组成 Collectd InfluxdDB Grafana Collectd 是一个守护(daemon)进程&#xff0c;用来…...

JavaCollection集合

5 Collection集合 5.1 Collection集合概述 是单列集合的顶层接口,它表示一组对象,这些对象也称Collection元素JDK不提供此接口的直接实现,它提供更具体的子接口(Set 和 List)实现package ceshi;import java.util.AbstractCollection; import java.util.ArrayList; import…...

C++中string的用法

博主简介&#xff1a;Hello大家好呀&#xff0c;我是陈童学&#xff0c;一个与你一样正在慢慢前行的人。 博主主页&#xff1a;陈童学哦 所属专栏&#xff1a;CSTL 前言&#xff1a;Hello各位小伙伴们好&#xff01;欢迎来到本专栏CSTL的学习&#xff0c;本专栏旨在帮助大家了解…...

目标检测YOLO实战应用案例100讲-基于深度学习的交通场景多尺度目标检测算法研究与应用

目录 基于深度学习的交通目标检测算法研究 传统的目标检测算法 基于深度学习的目标检测算法 </...

面试:vue事件绑定修饰符

stop - 调用 event.stopPropagation()。 prevent - 调用 event.preventDefault()。 trim 自动过滤用户输入的首尾空格 number 将输出字符串转为Number类型 enter 回车键 capture - 添加事件侦听器时使用 capture 模式。 self - 只当事件是从侦听器绑定的元素本身触发时才触发…...

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)

说明&#xff1a; 想象一下&#xff0c;你正在用eNSP搭建一个虚拟的网络世界&#xff0c;里面有虚拟的路由器、交换机、电脑&#xff08;PC&#xff09;等等。这些设备都在你的电脑里面“运行”&#xff0c;它们之间可以互相通信&#xff0c;就像一个封闭的小王国。 但是&#…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...

作为测试我们应该关注redis哪些方面

1、功能测试 数据结构操作&#xff1a;验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化&#xff1a;测试aof和aof持久化机制&#xff0c;确保数据在开启后正确恢复。 事务&#xff1a;检查事务的原子性和回滚机制。 发布订阅&#xff1a;确保消息正确传递。 2、性…...