國密 SM2 加密完全指南:金鑰生成、加密解密與數位簽章實戰

加密編碼編碼、雜湊與 QR Code

什麼是國密 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 對稱加密,即可滿足國密合規要求。工具庫提供 SM2、SM3、SM4 三個線上工具,瀏覽器本地處理,資料零上傳。

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