惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Proofpoint News Feed
V
V2EX
博客园_首页
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Recent Announcements
Recent Announcements
博客园 - 司徒正美
Microsoft Security Blog
Microsoft Security Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Latest news
Latest news
Vercel News
Vercel News
The Register - Security
The Register - Security
T
The Exploit Database - CXSecurity.com
S
Schneier on Security
N
Netflix TechBlog - Medium
WordPress大学
WordPress大学
小众软件
小众软件
L
Lohrmann on Cybersecurity
GbyAI
GbyAI
P
Privacy & Cybersecurity Law Blog
T
Tor Project blog
AWS News Blog
AWS News Blog
美团技术团队
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
K
Kaspersky official blog
B
Blog RSS Feed
G
Google Developers Blog
量子位
大猫的无限游戏
大猫的无限游戏
Google DeepMind News
Google DeepMind News
Scott Helme
Scott Helme
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
I
Intezer
雷峰网
雷峰网
Martin Fowler
Martin Fowler
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Blog — PlanetScale
Blog — PlanetScale
IT之家
IT之家
F
Full Disclosure
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 【当耐特】
The Hacker News
The Hacker News
U
Unit 42
S
SegmentFault 最新的问题
I
InfoQ
aimingoo的专栏
aimingoo的专栏
Y
Y Combinator Blog
宝玉的分享
宝玉的分享
罗磊的独立博客
Spread Privacy
Spread Privacy
C
CERT Recently Published Vulnerability Notes

博客园 - 江城2211

大数值的精度与格式化显示问题 【知识总结】数据库的事务、并发与锁管理 基于数据源连接,动态构造JPA上下文EntityManager 【转载】使用了HTTPS为啥还要接口数据加密? RSA加密算法,加解密、签名示例 【知识总结】JVM线程堆栈中的基础概念解读 【问题记录】JVM进程崩溃(hs_err_pid.log致命错误日志) [问题记录】存在视图依赖的数据表,DDL修改字段比如做扩容等注意事项 【编码技巧】批量校验或处理关联引用数据的优化总结 【问题总结】Garmin路线无法同步和地图坐标偏移的解决办法 【工具推荐】磁盘IO检测工具之Diskspd 【编码技巧】总结一个稳定而高效的方法,将二维关系数据转换为树形结构 【编程技巧】SQL脚本快速生成随机测试数据 【编程技巧】结合JPA通用分页与排序技术,支持百万级以上数据的DML批量处理方案 【使用技巧】CodeDecom.exe批量反编译JAR包+Beyond Compare对比 【问题记录】Cause: java.sql.SQLRecoverableException: No more data to read from socket JDBC与各数据库产品连接的驱动及URL示例 【问题记录】使用PowerDesigner连接数据库并反向工程生成所有表及关系 使用tcpdump抓取网络包,在wareshark查看对应请求及响应的原始报文
国密SM2算法,加密、签名示例
江城2211 · 2025-09-10 · via 博客园 - 江城2211

Posted on 2025-09-10 20:37  江城2211  阅读(107)  评论()    收藏  举报

Java代码SM2算法加解密、签名验签的实现Demo:

package com.example.demo;


import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.security.Security;


public final class SM2Demo {


    static {
        Security.addProvider(new BouncyCastleProvider());
    }


    /* ---------- 密钥对 ---------- */
    public static AsymmetricCipherKeyPair genKeyPair() {
        X9ECParameters sm2 = GMNamedCurves.getByName("sm2p256v1");
        ECDomainParameters domain = new ECDomainParameters(sm2.getCurve(), sm2.getG(), sm2.getN());
        ECKeyPairGenerator gen = new ECKeyPairGenerator();
        gen.init(new ECKeyGenerationParameters(domain, new SecureRandom()));
        return gen.generateKeyPair();
    }


    /* ---------- 加密 ---------- */
    public static String encrypt(String hexPubKey, String plain) throws Exception {
        X9ECParameters sm2 = GMNamedCurves.getByName("sm2p256v1");
        ECDomainParameters domain = new ECDomainParameters(sm2.getCurve(), sm2.getG(), sm2.getN());
        ECPoint pubPoint = sm2.getCurve().decodePoint(Hex.decode(hexPubKey));
        ECPublicKeyParameters pubKey = new ECPublicKeyParameters(pubPoint, domain);


        SM2Engine engine = new SM2Engine();
        engine.init(true, new ParametersWithRandom(pubKey, new SecureRandom()));
        byte[] cipher = engine.processBlock(plain.getBytes(), 0, plain.getBytes().length);
        return Hex.toHexString(cipher);
    }


    /* ---------- 解密 ---------- */
    public static String decrypt(String hexPriKey, String hexCipher) throws Exception {
        X9ECParameters sm2 = GMNamedCurves.getByName("sm2p256v1");
        ECDomainParameters domain = new ECDomainParameters(sm2.getCurve(), sm2.getG(), sm2.getN());
        BigInteger d = new BigInteger(hexPriKey, 16);
        ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(d, domain);


        SM2Engine engine = new SM2Engine();
        engine.init(false, priKey);
        byte[] plain = engine.processBlock(Hex.decode(hexCipher), 0, Hex.decode(hexCipher).length);
        return new String(plain);
    }


    /* ---------- 签名 ---------- */
    public static String sign(String hexPriKey, String id, String plain) throws Exception {
        X9ECParameters sm2 = GMNamedCurves.getByName("sm2p256v1");
        ECDomainParameters domain = new ECDomainParameters(sm2.getCurve(), sm2.getG(), sm2.getN());
        BigInteger d = new BigInteger(hexPriKey, 16);
        ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(d, domain);


        SM2Signer signer = new SM2Signer();
        CipherParameters param = new ParametersWithID(priKey, id.getBytes());
        signer.init(true, param);
        signer.update(plain.getBytes(), 0, plain.getBytes().length);
        byte[] sig = signer.generateSignature();
        return Hex.toHexString(sig);
    }


    /* ---------- 验签 ---------- */
    public static boolean verify(String hexPubKey, String id, String plain, String hexSig) throws Exception {
        X9ECParameters sm2 = GMNamedCurves.getByName("sm2p256v1");
        ECDomainParameters domain = new ECDomainParameters(sm2.getCurve(), sm2.getG(), sm2.getN());
        ECPoint pubPoint = sm2.getCurve().decodePoint(Hex.decode(hexPubKey));
        ECPublicKeyParameters pubKey = new ECPublicKeyParameters(pubPoint, domain);


        SM2Signer signer = new SM2Signer();
        CipherParameters param = new ParametersWithID(pubKey, id.getBytes());
        signer.init(false, param);
        signer.update(plain.getBytes(), 0, plain.getBytes().length);
        return signer.verifySignature(Hex.decode(hexSig));
    }


    /* ---------- 演示 ---------- */
    public static void main(String[] args) throws Exception {
        AsymmetricCipherKeyPair kp = genKeyPair();
        String pubHex = Hex.toHexString(((ECPublicKeyParameters) kp.getPublic()).getQ().getEncoded(false));
        String priHex = ((ECPrivateKeyParameters) kp.getPrivate()).getD().toString(16);


        System.out.println("公钥: " + pubHex);
        System.out.println("私钥: " + priHex);


        String plain = "hello 国密 SM2";
        System.out.println("原始数:" + plain);
        String cipher = encrypt(pubHex, plain);
        System.out.println("加密后: " + cipher);


        String recovered = decrypt(priHex, cipher);
        System.out.println("解密后: " + recovered);


        String id = "1234567812345678";          // 国密标准推荐 16 字节 ID
        String sig = sign(priHex, id, plain);
        System.out.println("签名  : " + sig);
        boolean ok = verify(pubHex, id, plain, sig);
        System.out.println("验签结果: " + ok);
    }
}

pom依赖引入 :

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.70</version> <!-- 版本号可根据需要更新,1.70及以上版本对SM2支持完善 -->
</dependency>

参考文章:https://cloud.tencent.com/developer/article/2499894