bouncycastle(BC) 实现SM2国密加解密、签名、验签
https://www.cnblogs.com/dashou/p/14656458.html
SM2国密加解密一个类就够了
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.65</version>
</dependency>
版本库经测试适用(1.61-1.68) 如有问题请留言纠正
本文参考博主 「RisenMyth」:https://blog.csdn.net/RisenMyth/article/details/107212156
若要使用老版本的写法 可以参考 https://blog.csdn.net/fenglongmiao/article/details/79501757

import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;
import org.springframework.stereotype.Component; import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.ByteArrayInputStream;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64; /**
* bcprov-jdk15on 版本适用(1.61-1.68)
* @author dashou
* @date 2021-4-13
*/
@Component
public class SM2Util {
private BouncyCastleProvider provider;
// 获取SM2相关参数
private X9ECParameters parameters;
// 椭圆曲线参数规格
private ECParameterSpec ecParameterSpec;
// 获取椭圆曲线KEY生成器
private KeyFactory keyFactory; private SM2Util(){
try {
provider = new BouncyCastleProvider();
parameters = GMNamedCurves.getByName("sm2p256v1");
ecParameterSpec = new ECParameterSpec(parameters.getCurve(),
parameters.getG(), parameters.getN(), parameters.getH());
keyFactory = KeyFactory.getInstance("EC", provider);
} catch (Exception e) {
e.printStackTrace();
}
} /**
* SM2算法生成密钥对
*
* @return 密钥对信息
*/
public KeyPair generateSm2KeyPair() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException {
final ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");
// 获取一个椭圆曲线类型的密钥对生成器
final KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", provider);
SecureRandom random = new SecureRandom();
// 使用SM2的算法区域初始化密钥生成器
kpg.initialize(sm2Spec, random);
// 获取密钥对
KeyPair keyPair = kpg.generateKeyPair();
return keyPair;
} /**
* 加密
*
* @param input 待加密文本
* @param pubKey 公钥
* @return
*/
public String encode(String input, String pubKey)
throws NoSuchPaddingException, NoSuchAlgorithmException,
BadPaddingException, IllegalBlockSizeException,
InvalidKeySpecException, InvalidKeyException {
// 获取SM2相关参数
X9ECParameters parameters = GMNamedCurves.getByName("sm2p256v1");
// 椭圆曲线参数规格
ECParameterSpec ecParameterSpec = new ECParameterSpec(parameters.getCurve(), parameters.getG(), parameters.getN(), parameters.getH());
// 将公钥HEX字符串转换为椭圆曲线对应的点
ECPoint ecPoint = parameters.getCurve().decodePoint(Hex.decode(pubKey));
// 获取椭圆曲线KEY生成器
KeyFactory keyFactory = KeyFactory.getInstance("EC", provider);
BCECPublicKey key = (BCECPublicKey) keyFactory.generatePublic(new ECPublicKeySpec(ecPoint, ecParameterSpec));
// 获取SM2加密器
Cipher cipher = Cipher.getInstance("SM2", provider);
// 初始化为加密模式
cipher.init(Cipher.ENCRYPT_MODE, key);
// 加密并编码为base64格式
return Base64.getEncoder().encodeToString(cipher.doFinal(input.getBytes()));
} /**
* 解密
*
* @param input 待解密文本
* @param prvKey 私钥
* @return
*/
public byte[] decoder(String input, String prvKey) throws NoSuchPaddingException, NoSuchAlgorithmException,
InvalidKeySpecException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
// 获取SM2加密器
Cipher cipher = Cipher.getInstance("SM2", provider);
// 将私钥HEX字符串转换为X值
BigInteger bigInteger = new BigInteger(prvKey, 16);
BCECPrivateKey privateKey = (BCECPrivateKey) keyFactory.generatePrivate(new ECPrivateKeySpec(bigInteger,
ecParameterSpec));
// 初始化为解密模式
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// 解密
return cipher.doFinal(Base64.getDecoder().decode(input));
} /**
* 签名
*
* @param plainText 待签名文本
* @param prvKey 私钥
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @throws InvalidKeyException
* @throws SignatureException
*/
public String sign(String plainText, String prvKey) throws NoSuchAlgorithmException, InvalidKeySpecException,
InvalidKeyException, SignatureException {
// 创建签名对象
Signature signature = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString(), provider);
// 将私钥HEX字符串转换为X值
BigInteger bigInteger = new BigInteger(prvKey, 16);
BCECPrivateKey privateKey = (BCECPrivateKey) keyFactory.generatePrivate(new ECPrivateKeySpec(bigInteger,
ecParameterSpec));
// 初始化为签名状态
signature.initSign(privateKey);
// 传入签名字节
signature.update(plainText.getBytes());
// 签名
return Base64.getEncoder().encodeToString(signature.sign());
} public boolean verify(String plainText, String signatureValue, String pubKey) throws NoSuchAlgorithmException, InvalidKeySpecException,
InvalidKeyException, SignatureException {
// 创建签名对象
Signature signature = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString(), provider);
// 将公钥HEX字符串转换为椭圆曲线对应的点
ECPoint ecPoint = parameters.getCurve().decodePoint(Hex.decode(pubKey));
BCECPublicKey key = (BCECPublicKey) keyFactory.generatePublic(new ECPublicKeySpec(ecPoint, ecParameterSpec));
// 初始化为验签状态
signature.initVerify(key);
signature.update(plainText.getBytes());
return signature.verify(Base64.getDecoder().decode(signatureValue));
} /**
* 证书验签
*
* @param certStr 证书串
* @param plaintext 签名原文
* @param signValueStr 签名产生签名值 此处的签名值实际上就是 R和S的sequence
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
* @throws SignatureException
*/
public boolean certVerify(String certStr, String plaintext, String signValueStr)
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, CertificateException { byte[] signValue = Base64.getDecoder().decode(signValueStr);
/*
* 解析证书
*/
CertificateFactory factory = new CertificateFactory();
X509Certificate certificate = (X509Certificate) factory
.engineGenerateCertificate(new ByteArrayInputStream(Base64.getDecoder().decode(certStr)));
// 验证签名
Signature signature = Signature.getInstance(certificate.getSigAlgName(), provider);
signature.initVerify(certificate);
signature.update(plaintext.getBytes());
return signature.verify(signValue);
} public static void main(String[] args) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException {
String str = "看看能不能一次通过";
SM2Util sm2 = new SM2Util();
KeyPair keyPair = sm2.generateSm2KeyPair();
BCECPrivateKey privateKey = (BCECPrivateKey) keyPair.getPrivate();
BCECPublicKey publicKey = (BCECPublicKey) keyPair.getPublic(); // 拿到密钥
String pubKey = new String(Hex.encode(publicKey.getQ().getEncoded(true)));
String prvKey = privateKey.getD().toString(16);
System.out.println("Private Key: " + prvKey);
System.out.println("Public Key: " + pubKey);
// 加解密测试
try {
System.out.println("加密前:" + str);
String encode = sm2.encode(str, pubKey);
System.out.println("加密后:" + encode);
String decoder = new String(sm2.decoder(encode, prvKey));
System.out.println("解密后:" + decoder);
} catch (Exception e) {
System.out.println("加解密测试错误");
}
// 签名和验签测试
try {
System.out.println("签名源数据:" + str);
String signStr = sm2.sign(str, prvKey);
System.out.println("签名后数据:" + signStr);
boolean verify = sm2.verify(str, signStr, pubKey);
System.out.println("签名验证结果:" + verify);
} catch (Exception e) {
System.out.println("签名和验签测试错误");
}
}
}

bouncycastle(BC) 实现SM2国密加解密、签名、验签的更多相关文章
- RSACryptoServiceProvider加密解密签名验签和DESCryptoServiceProvider加解密
原文:RSACryptoServiceProvider加密解密签名验签和DESCryptoServiceProvider加解密 C#在using System.Security.Cryptograph ...
- C# RSACryptoServiceProvider加密解密签名验签和DESCryptoServic
C#在using System.Security.Cryptography下有 DESCryptoServiceProvider RSACryptoServiceProvider DESCryptoS ...
- js rsa sign使用笔记(加密,解密,签名,验签)
你将会收获: js如何加密, 解密 js如何签名, 验签 js和Java交互如何相互解密, 验签(重点) 通过谷歌, 发现jsrsasign库使用者较多. 查看api发现这个库功能很健全. 本文使用方 ...
- C# RSA加解密与验签,AES加解密,以及与JAVA平台的密文加解密
前言: RSA算法是利用公钥与密钥对数据进行加密验证的一种算法.一般是拿私钥对数据进行签名,公钥发给友商,将数据及签名一同发给友商,友商利用公钥对签名进行验证.也可以使用公钥对数据加密,然后用私钥对数 ...
- Java RSA 加密 解密 签名 验签
原文:http://gaofulai1988.iteye.com/blog/2262802 import java.io.FileInputStream; import java.io.FileOut ...
- SM2国密证书合法性验证
通常我们遇到过的X509证书都是基于RSA-SHA1算法的,目前国家在大力推行国密算法,未来银行发行的IC卡也都是基于PBOC3.0支持国密算法的,因此我们来学习一下如何验证SM2国密证书的合法性.至 ...
- SM2的非对称加解密java工具类
maven依赖 <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov- ...
- [Python3] RSA的加解密和签名/验签实现 -- 使用pycrytodome
Crypto 包介绍: pycrypto,pycrytodome 和 crypto 是一个东西,crypto 在 python 上面的名字是 pycrypto 它是一个第三方库,但是已经停止更新,所以 ...
- RSA密钥生成、加密解密、签名验签
RSA 非对称加密公钥加密,私钥解密 私钥签名,公钥验签 下面是生成随机密钥对: //随机生成密钥对 KeyPairGenerator keyPairGen = null; try { keyPair ...
- 支付接口中常用的加密解密以及验签rsa,md5,sha
一.常用加密类型分类 1.对称加密:采用单钥对信息进行加密和解密,即同一个秘钥既可以对信息进行加密,也可以进行解密.此类型称之为对称加密.特点速度快,常用于对大量数据信息或文件加密时使用.常用例子:D ...
随机推荐
- Failed to connect to github.com port 443: Connection refused问题解决
解决办法: 1.找到github的ip地址:查找链接 2.找到本地的hosts文件.我的hosts文件路劲为:C:\Windows\System32\drivers\etc 3.在hosts文件最后添 ...
- 前端导出excel文件,后端返回二进制文件 application/octet-stream 前端处理数据并下载excel文件
通过URL.createObjectURL(blob)可以获取当前文件的一个内存URL const href = URL.createObjectURL(res.data); const box = ...
- 第三方的开源库FluentVaidation校验字段的
内置的 using System.ComponentModel.DataAnnotations; 基本使用: 1. 安装包 FluentValidation.AspNetCOre 2. 注册服务 bu ...
- 警告:攻击者利用 SnoarQube 漏洞盗取国内多个机构的大量源码!
2021 年 10 月 22 日,国外知名媒体 cybernews 发文称,有未知攻击者攻击并渗透了博世 iSite 的服务器,并盗取了这家制造业巨头的 5G 物联网连接平台的源代码. 攻击者声称通过 ...
- 题解:AT_abc370_c [ABC370C] Word Ladder
题目传送门 luogu观看 简要题意 给两个序列 \(S\) 和 \(T\),输出的第一个数是它能改变的总个数,后面跟着的第 \(i\) 个是改变 \(i\) 个数之后,字典序最小的结果. 思路 当 ...
- JavaScript 语句后可以省略分号么?
摘自知乎:https://www.zhihu.com/question/20298345 田乐:加与不加是风格问题,风格争议不需要有个定论.关键的问题在于如何"争论",处理好冲突, ...
- Java高并发之线程的实现方式,含Lamabda表达式
Java中线程实现的方式 在 Java 中实现多线程有4种手段: 1.继承 Thread 类 2.实现 Runnable 接口 3.匿名内部类 4.Lambda表达式实现 实现 Runnable 接口 ...
- nginx配置tomcat的反向代理记录二,根据访问的路径跳转到不同端口的tomcat服务器
实现效果:使用 nginx 反向代理,根据访问的路径跳转到不同端口的服务中. 设置nginx 监听端口为 9001,访问 http://192.168.17.129:9001/vod/ 直接跳转到 1 ...
- SpringBoot入门到精通(十三)日志:别小看它,否则吃亏的是自己!学会你也可以设计架构
别小看他,当你面对的时候,就会知道,多么痛的领悟! 如何在 Spring Boot 中使用 Logback 记录详细的日志? 整合LogBack,Log4J...等,是不是很多方法!但需要注意,我讲的 ...
- 在昇腾Ascend 910B上运行Qwen2.5推理
目前在国产 AI 芯片,例如昇腾 NPU 上运行大模型是一项广泛且迫切的需求,然而当前的生态还远未成熟.从底层芯片的算力性能.计算架构的算子优化,到上层推理框架对各种模型的支持及推理加速,仍有很多需要 ...