国密算法是由中国国家密码管理局制定的商用密码标准,包括:
在安全通信中,双方需要在不安全的信道上协商出相同的会话密钥,用于后续对称加密。SM2密钥协商协议解决了以下问题:
步骤 | 角色A(发起方) | 角色B(响应方) |
---|---|---|
1 | 生成临时密钥对 (rA, RA) | 生成临时密钥对 (rB, RB) |
2 | 发送RA给B | 发送RB给A |
3 | 使用双方公钥和临时公钥计算共享密钥 | 使用双方公钥和临时公钥计算共享密钥 |
共享密钥 = 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
:静态公钥派生参数
<dependency>
<groupId>org.bouncycastlegroupId>
<artifactId>bcprov-jdk15onartifactId>
<version>1.65version>
dependency>
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.Security;
public class SM2KeyExchange {
static {
Security.addProvider(new BouncyCastleProvider()); // 添加BC提供者
}
}
/**
* 生成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();
}
/**
* 发起方计算共享密钥
* @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();
}
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;
}
}
场景 | 说明 |
---|---|
物联网安全通信 | 设备与云端协商会话密钥,用于加密传感器数据 |
移动支付 | POS终端与支付网关建立安全通道 |
视频会议加密 | 参与方动态协商密钥,保证会议内容机密性 |
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国密算法的密钥协商协议,包含以下核心内容:
注意事项:生产环境请结合证书体系实现身份认证。
希望这篇文章对你有所帮助!如果觉得不错,别忘了点赞收藏哦!