国密SM2加密完全指南:密钥生成、加密解密与数字签名实战

加密编码(更新于 2026年6月2日)

什么是国密 SM2?

SM2 是中国国家密码管理局发布的非对称加密算法,基于椭圆曲线密码学(ECC),取代 RSA 成为国密标准。

对比项 SM2 RSA 2048
密钥长度 256 bit 2048 bit
安全强度 128 bit 112 bit
签名速度 ~0.5ms ~3ms
验证速度 ~1ms ~0.1ms
密钥长度比 1 8
国标 GM/T 0003 PKCS#1

SM2 用 256 位密钥达到 RSA 2048 位的安全强度,密钥更短、速度更快。


SM2 的三种用途

用途 说明 对应工具
加密/解密 用公钥加密,私钥解密 SM2 加密
数字签名 用私钥签名,公钥验证 SM2 签名
密钥协商 双方协商出共享密钥 ECDH 协议

第一步:生成 SM2 密钥对

使用工具库生成

  1. 打开 SM2 加密工具
  2. 点击"生成密钥对"
  3. 获得公钥和私钥

使用命令行生成

# 安装 gmssl
brew install gmssl  # macOS
# 或从 https://github.com/guanzhi/GmSSL/releases 下载

# 生成 SM2 密钥对
gmssl sm2 -genkey -out sm2.key

# 查看密钥
gmssl sm2 -in sm2.key -text

使用 JavaScript 生成

import { sm2 } from 'sm-crypto';

// 生成密钥对
const keyPair = sm2.generateKeyPairHex();
// keyPair.privateKey → 私钥(64位十六进制)
// keyPair.publicKey  → 公钥(128位十六进制,04 + X + Y)

console.log('私钥:', keyPair.privateKey);
console.log('公钥:', keyPair.publicKey);

密钥格式说明

SM2 公钥格式:
04 || X(32字节) || Y(32字节)
↓
04 + 64位十六进制X + 64位十六进制Y
总长度:130个十六进制字符(65字节)

SM2 私钥格式:
32字节随机数
总长度:64个十六进制字符(32字节)

第二步:SM2 加密与解密

加密流程

明文 → SM2加密(公钥) → 密文(C1 || C3 || C2)
  • C1:椭圆曲线点(65字节)
  • C3:SM3 哈希值(32字节)
  • C2:密文数据

使用工具库加密

  1. 打开 SM2 加密工具
  2. 粘贴公钥
  3. 输入要加密的明文
  4. 选择密文格式(C1C3C2 或 C1C2C3)
  5. 点击"加密"获得密文

使用 JavaScript 加密

import { sm2 } from 'sm-crypto';

const publicKey = '04...'; // 130位十六进制
const privateKey = '...';  // 64位十六进制

// 加密(默认 C1C3C2 格式)
const cipherText = sm2.doEncrypt('Hello 国密', publicKey, 1);
// 参数 1 = C1C3C2 格式(国标推荐)
// 参数 0 = C1C2C3 格式(旧版兼容)

console.log('密文:', cipherText);

// 解密
const plainText = sm2.doDecrypt(cipherText, privateKey, 1);
console.log('明文:', plainText); // "Hello 国密"

密文编码格式

格式 说明 使用场景
C1C3C2 国标推荐格式 新项目(默认)
C1C2C3 旧版格式 兼容旧系统
ASN.1 DER 编码 Java/C# 互操作

第三步:SM2 数字签名

签名流程

消息 → SM3哈希 → SM2签名(私钥) → 签名值(r, s)

使用工具库签名

  1. 打开 SM2 加密工具
  2. 切换到"签名"标签
  3. 输入私钥和待签名消息
  4. 点击"签名"获得签名值

使用 JavaScript 签名

import { sm2 } from 'sm-crypto';

const privateKey = '...';
const publicKey = '04...';

// 签名(自动对消息做 SM3 哈希)
const signature = sm2.doSignature('待签名消息', privateKey);
console.log('签名:', signature);

// 验证签名
const verified = sm2.doVerifySignature(
  '待签名消息',
  signature,
  publicKey
);
console.log('验证结果:', verified); // true

带用户 ID 的签名

SM2 签名默认使用用户 ID 1234567812345678(国标默认值),可以自定义:

// 签名时指定用户 ID
const sig = sm2.doSignature('消息', privateKey, {
  userId: 'customUserId'
});

// 验证时使用相同的用户 ID
const valid = sm2.doVerifySignature('消息', sig, publicKey, {
  userId: 'customUserId'
});

SM2 vs RSA:何时选择?

场景 推荐 原因
国内政务系统 SM2 国密合规要求
国内金融系统 SM2 银联/人行要求
国际标准系统 RSA 国际兼容性
移动端加密 SM2 密钥短,计算快
跨境数据交换 RSA 国际通用

国密三件套:SM2 + SM3 + SM4

算法 类型 用途 工具
SM2 非对称 加密/签名/密钥协商 SM2 工具
SM3 哈希 消息摘要(类似 SHA-256) SM3 工具
SM4 对称 数据加密(类似 AES-128) SM4 工具

典型组合:SM2 + SM4 混合加密

1. 生成随机 SM4 密钥
2. 用 SM4 加密大数据(快)
3. 用 SM2 公钥加密 SM4 密钥(安全传输)
4. 发送:SM2(SM4密钥) + SM4(数据)
import { sm2, sm4 } from 'sm-crypto';

// 1. 生成随机 SM4 密钥
const sm4Key = crypto.getRandomValues(new Uint8Array(16));
const sm4KeyHex = Array.from(sm4Key).map(b => b.toString(16).padStart(2, '0')).join('');

// 2. 用 SM4 加密数据
const encryptedData = sm4.encrypt(plainText, sm4KeyHex);

// 3. 用 SM2 加密 SM4 密钥
const encryptedKey = sm2.doEncrypt(sm4KeyHex, sm2PublicKey, 1);

// 发送:encryptedKey + encryptedData

常见问题

SM2 密文长度为什么比明文长很多?

SM2 密文 = C1(65字节)+ C3(32字节)+ C2(明文长度),所以密文比明文多 97 字节。这是非对称加密的特性,大数据建议用 SM2+SM4 混合加密

SM2 和 ECDSA 有什么区别?

SM2 使用国密指定的椭圆曲线(sm2p256v1),ECDSA 使用 NIST 曲线(P-256)。算法逻辑相似,但曲线参数不同,不兼容

如何在 Java 中使用 SM2?

// 使用 Bouncy Castle + 国密扩展
Security.addProvider(new BouncyCastleProvider());

// 生成密钥对
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC");
kpg.initialize(new ECParameterSpec(...)); // SM2 曲线参数
KeyPair kp = kpg.generateKeyPair();

总结

SM2 是国密体系的核心非对称加密算法,256 位密钥即可达到 RSA 2048 位的安全强度。掌握密钥生成、加密解密、数字签名三大操作,配合 SM3 哈希和 SM4 对称加密,即可满足国密合规要求。工具库提供 SM2SM3SM4 三个在线工具,浏览器本地处理,数据零上传。

#国密#SM2#非对称加密#数字签名#加密教程