一、代碼運行結果
二、國密算法與密鑰協商背景
2.1 什么是國密算法?
國密算法是由中國國家密碼管理局制定的商用密碼標準,包括:
- SM2:橢圓曲線公鑰密碼算法(非對稱加密/簽名/密鑰協商)
- SM3:密碼雜湊算法(哈希)
- SM4:分組密碼算法(對稱加密)
2.2 密鑰協商的意義
在安全通信中,雙方需要在不安全的信道上協商出相同的會話密鑰,用于后續對稱加密。SM2密鑰協商協議解決了以下問題:
- 避免預先共享密鑰
- 抵抗中間人攻擊
- 支持雙向身份認證
三、SM2密鑰協商原理詳解
3.1 核心流程(基于ECMQV協議)
步驟 | 角色A(發起方) | 角色B(響應方) |
---|---|---|
1 | 生成臨時密鑰對 (rA, RA) | 生成臨時密鑰對 (rB, RB) |
2 | 發送RA給B | 發送RB給A |
3 | 使用雙方公鑰和臨時公鑰計算共享密鑰 | 使用雙方公鑰和臨時公鑰計算共享密鑰 |
3.2 關鍵公式
共享密鑰 = KDF( x_U \cdot (d_A + r_A \cdot s_A) \cdot (P_B + [s_B] \cdot R_B) )
x_U
:橢圓曲線點坐標的x分量d_A
:A方私鑰r_A
:A方臨時私鑰s_A/s_B
:靜態公鑰派生參數
四、Java實現環境準備
4.1 依賴配置
<!-- Bouncy Castle國密支持 -->
<dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><version>1.65</version>
</dependency>
4.2 初始化安全提供者
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.Security;public class SM2KeyExchange {static {Security.addProvider(new BouncyCastleProvider()); // 添加BC提供者}
}
五、Java核心代碼實現(含詳細注釋)
5.1 密鑰對生成工具類
/*** 生成SM2靜態密鑰對*/public static KeyPair generateStaticKeyPair() throws Exception {ECParameterSpec sm2Spec = ECNamedCurveTable.getParameterSpec("sm2p256v1");KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC");kpg.initialize(sm2Spec, new SecureRandom());return kpg.generateKeyPair();}/*** 生成臨時密鑰對(用于密鑰協商)*/public static KeyPair generateEphemeralKeyPair() throws Exception {return generateStaticKeyPair();}
5.2 密鑰協商核心邏輯
/*** 發起方計算共享密鑰* @param staticKeyPair 己方靜態密鑰對* @param ephemeralKeyPair 己方臨時密鑰對* @param otherStaticPub 對方靜態公鑰* @param otherEphemeralPub 對方臨時公鑰* @return 共享密鑰字節數組*/public static byte[] initiatorAgreement(KeyPair staticKeyPair,KeyPair ephemeralKeyPair,PublicKey otherStaticPub,PublicKey otherEphemeralPub) {ECMQVBasicAgreement agreement = new ECMQVBasicAgreement();// 構建本地私鑰參數(包含靜態私鑰、臨時私鑰和臨時公鑰)MQVPrivateParameters localParams = new MQVPrivateParameters((ECPrivateKeyParameters) convertToBC(staticKeyPair.getPrivate()),(ECPrivateKeyParameters) convertToBC(ephemeralKeyPair.getPrivate()),(ECPublicKeyParameters) convertToBC(ephemeralKeyPair.getPublic()));// 初始化時僅傳遞本地私鑰參數agreement.init(localParams); // 構建遠端公鑰參數(對方靜態公鑰 + 臨時公鑰)MQVPublicParameters remoteParams = new MQVPublicParameters((ECPublicKeyParameters) convertToBC(otherStaticPub),(ECPublicKeyParameters) convertToBC(otherEphemeralPub));// 計算協商結果時傳遞遠端公鑰參數BigInteger sharedSecret = agreement.calculateAgreement(remoteParams); return sharedSecret.toByteArray();}
5.3 密鑰派生函數(KDF)示例
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.generators.KDF2BytesGenerator;/*** 國密KDF實現*/
public class SM2KDF {/*** 使用SM3進行密鑰派生* @param sharedSecret 原始共享密鑰* @param keyLength 目標密鑰長度(單位:字節)*/public static byte[] kdf(byte[] sharedSecret, int keyLength) {Digest digest = new SM3Digest();KDF2BytesGenerator kdf = new KDF2BytesGenerator(digest);kdf.init(new KDFParameters(sharedSecret, new byte[0])); // 無鹽值byte[] derivedKey = new byte[keyLength];kdf.generateBytes(derivedKey, 0, keyLength);return derivedKey;}
}
六、應用場景分析
6.1 典型應用場景
場景 | 說明 |
---|---|
物聯網安全通信 | 設備與云端協商會話密鑰,用于加密傳感器數據 |
移動支付 | POS終端與支付網關建立安全通道 |
視頻會議加密 | 參與方動態協商密鑰,保證會議內容機密性 |
6.2 協議優勢
- 前向安全性:臨時密鑰對使用后立即銷毀,即使長期密鑰泄露,歷史會話仍安全
- 雙向認證:可結合數字證書驗證雙方身份
- 國密合規:滿足等保2.0和金融行業安全要求
七、注意事項與優化建議
7.1 安全注意事項
- 隨機數質量:密鑰協商中的臨時密鑰必須使用密碼學安全隨機數生成器
- 密鑰派生:必須使用KDF(如SM3)處理原始共享密鑰,避免直接使用
- 密鑰生命周期:協商出的會話密鑰應定期更新(建議不超過24小時)
7.2 性能優化技巧
- 預生成臨時密鑰:在高并發場景中預生成臨時密鑰池
- 硬件加速:使用支持SM2的HSM(硬件安全模塊)提升計算速度
- 緩存復用:在短連接場景中復用會話密鑰(需權衡安全性)
八、完整測試案例
public static void main(String[] args) throws Exception {Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());// 1. 生成雙方靜態密鑰對KeyPair aliceStaticKey = generateStaticKeyPair();KeyPair bobStaticKey = generateStaticKeyPair();// 2. 生成臨時密鑰對KeyPair aliceEphemeralKey = generateEphemeralKeyPair();KeyPair bobEphemeralKey = generateEphemeralKeyPair();// 3. Alice作為發起方計算共享密鑰byte[] aliceSharedSecret = SM2KeyAgreement.initiatorAgreement(aliceStaticKey,aliceEphemeralKey,bobStaticKey.getPublic(),bobEphemeralKey.getPublic());// 4. Bob作為發起方計算共享密鑰(對稱操作)byte[] bobSharedSecret = SM2KeyAgreement.initiatorAgreement(bobStaticKey,bobEphemeralKey,aliceStaticKey.getPublic(),aliceEphemeralKey.getPublic());// 5. 驗證密鑰一致性System.out.println("密鑰協商是否成功: " +Arrays.equals(aliceSharedSecret, bobSharedSecret));// 6. 派生實際加密密鑰(生成128位SM4密鑰)byte[] sm4Key = Arrays.copyOfRange(aliceSharedSecret, 0, 16);System.out.println("SM4密鑰: " + Hex.toHexString(sm4Key));
九、總結
本文完整實現了基于SM2國密算法的密鑰協商協議,包含以下核心內容:
- 原理剖析:基于ECMQV協議的密鑰交換流程
- 代碼實現:靜態/臨時密鑰生成、協商計算、KDF派生
- 場景分析:物聯網、金融支付等典型應用場景
注意事項:生產環境請結合證書體系實現身份認證。
希望這篇文章對你有所幫助!如果覺得不錯,別忘了點贊收藏哦!