一、SM2算法概述
SM2算法是中国国家密码管理局于2010年发布的椭圆曲线公钥密码算法,属于国密算法体系的核心组成部分。它基于椭圆曲线密码学(ECC)原理,提供数字签名、密钥交换和公钥加密三大功能,旨在替代传统的RSA等国际算法。
核心优势
高安全性:基于椭圆曲线离散对数难题(ECDLP),256位密钥即可达到RSA 3072位安全级别,当前无已知有效破解方法。
计算高效:密钥长度短,计算量小,在相同安全级别下,SM2的计算速度比RSA快,尤其在签名验证方面表现优异。
自主可控:作为国产算法,SM2避免了对外国技术的依赖,符合中国密码合规要求,已广泛应用于金融、政务等关键领域。
资源消耗低:嵌入式设备上SM2的RAM占用不超过8KB,适合物联网终端应用,而同等安全的RSA实现需要50KB以上内存。
二、SM2算法原理
椭圆曲线基础
SM2算法基于椭圆曲线方程 y2=x3+ax+b的数学难题。算法使用的椭圆曲线参数由国家密码管理局指定,确保安全性与标准化。
密钥生成
- 私钥:随机生成的256位整数 d
- 公钥:椭圆曲线上的点 P=[d]G,其中 G是曲线基点
加密流程
SM2加密采用”公钥协商 + 对称加密 + MAC校验”的组合机制:
- 生成随机数:发送方生成随机数 k,计算临时公钥 C1=[k]G
- 计算共享点:S=k⋅P=(x2,y2)
- 派生密钥:使用KDF函数生成对称密钥 t=KDF(x2∣∣y2,klen)
- 加密明文:C2=M⊕t
- 生成哈希值:C3=Hash(x2∣∣M∣∣y2)
- 输出密文:C=C1∣∣C3∣∣C2
解密流程
接收方使用私钥 d进行解密:
- 解析密文得到 C1、C3、C2
- 计算共享点 S=d⋅C1=(x2,y2)
- 派生密钥 t=KDF(x2∣∣y2,klen)
- 恢复明文 M=C2⊕t
- 验证哈希值 Hash(x2∣∣M∣∣y2)==C3
三、SpringBoot集成SM2实战
1. 项目依赖配置
在SpringBoot项目的pom.xml中添加BouncyCastle依赖:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15to18</artifactId>
<version>1.72</version>
</dependency>
如果使用Hutool工具包,可添加:
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.22</version>
</dependency>
2. SM2密钥对生成工具类
package com.example.util;
import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.BCUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import lombok.Data;
@Data
public class SM2Key {
/** 服务端加密公钥 */
private String serverPublicKey;
/** 服务端解密私钥 */
private String serverPrivateKey;
/** 客户端加密公钥 */
private String clientPublicKey;
/** 客户端解密私钥 */
private String clientPrivateKey;
}
public class SM2Util {
/**
* 生成前后端加解密密钥对
*/
public static SM2Key generate() {
SM2Key sm2Key = new SM2Key();
// 生成服务端密钥对
SM2 sm2 = SmUtil.sm2();
sm2Key.setServerPublicKey(HexUtil.encodeHexStr(
((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false)));
sm2Key.setClientPrivateKey(HexUtil.encodeHexStr(
BCUtil.encodeECPrivateKey(sm2.getPrivateKey())));
// 生成客户端密钥对
sm2 = SmUtil.sm2();
sm2Key.setClientPublicKey(HexUtil.encodeHexStr(
((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false)));
sm2Key.setServerPrivateKey(HexUtil.encodeHexStr(
BCUtil.encodeECPrivateKey(sm2.getPrivateKey())));
return sm2Key;
}
/**
* SM2加密
* @param publicKey 公钥
* @param data 明文数据
* @return 密文
*/
public static String encrypt(String publicKey, String data) {
return SmUtil.sm2(null, publicKey)
.encryptHex(data.getBytes(), KeyType.PublicKey)
.substring(2); // 去掉04前缀
}
/**
* SM2解密
* @param privateKey 私钥
* @param data 密文数据
* @return 明文
*/
public static String decrypt(String privateKey, String data) {
return SmUtil.sm2(privateKey, null)
.decryptStr(data.startsWith("04") ? data : "04" + data,
KeyType.PrivateKey);
}
}
3. 数字签名与验签
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
public class SM2SignUtil {
/**
* 生成数字签名
*/
public static byte[] sign(byte[] message, ECPrivateKeyParameters privateKey) {
SM2Signer signer = new SM2Signer();
signer.init(true, privateKey);
signer.update(message, 0, message.length);
return signer.generateSignature();
}
/**
* 验证数字签名
*/
public static boolean verify(byte[] message, byte[] signature,
ECPublicKeyParameters publicKey) {
SM2Signer signer = new SM2Signer();
signer.init(false, publicKey);
signer.update(message, 0, message.length);
return signer.verifySignature(signature);
}
}
4. 请求响应加解密拦截器
@Component
public class SM2EncryptInterceptor implements HandlerInterceptor {
@Autowired
private SM2Util sm2Util;
@Value("${sm2.client-public-key}")
private String clientPublicKey;
@Value("${sm2.server-private-key}")
private String serverPrivateKey;
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) {
// 解密请求参数
String encryptedData = request.getParameter("data");
if (StringUtils.hasText(encryptedData)) {
String decryptedData = sm2Util.decrypt(serverPrivateKey, encryptedData);
// 将解密后的数据放入请求属性中
request.setAttribute("decryptedData", decryptedData);
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) {
// 加密响应数据
if (modelAndView != null && modelAndView.getModel() != null) {
Object data = modelAndView.getModel().get("data");
if (data != null) {
String encryptedData = sm2Util.encrypt(clientPublicKey, data.toString());
modelAndView.getModel().put("data", encryptedData);
}
}
}
}
5. 配置拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private SM2EncryptInterceptor sm2EncryptInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(sm2EncryptInterceptor)
.addPathPatterns("/api/**") // 需要加密的接口路径
.excludePathPatterns("/api/public/**"); // 不需要加密的接口
}
}
6. Controller示例
@RestController
@RequestMapping("/api/user")
public class UserController {
@PostMapping("/login")
public Result login(@RequestBody LoginRequest request) {
// 请求数据已在拦截器中自动解密
// 业务逻辑处理
UserInfo userInfo = userService.login(request);
// 返回结果会自动加密
return Result.success(userInfo);
}
}
四、SM2 vs RSA对比
| 维度 | SM2(256位) | RSA(2048位) |
|---|---|---|
| 安全级别 | 等同RSA 3072位 | 中等 |
| 密钥长度 | 256位 | 2048位 |
| 计算速度 | 快(签名/验签效率高) | 慢 |
| 资源消耗 | 低(适合移动设备) | 高 |
| 签名长度 | 64字节 | 384字节 |
| 带宽占用 | 减少83% | 高 |
| 合规性 | 中国国家标准 | 国际标准 |
五、应用场景
1. 金融支付领域
- 银行卡交易、网上银行系统
- 数字人民币中的身份认证与数据加密
- 银联芯片卡规范明确将SM2作为首选非对称算法
2. 电子政务
- 政府公文流转、电子证照
- 税务系统中的数字签名
- 省级政务云平台采用SM2实现跨部门数据安全共享
3. 物联网与车联网
- 设备身份认证、数据加密传输
- 智能家居、智能交通等IoT场景
- 电力调度系统使用SM2实现厂站端身份认证
4. SSL证书
- 国密SSL证书(如SM2-WiSSL)用于网站HTTPS加密
- 国产浏览器访问https://开头的网站
六、注意事项
1. 密钥管理
- 公钥可以硬编码到前端,私钥必须放在服务器环境变量或配置中心
- 生产环境建议使用密钥管理系统(KMS)管理私钥
2. 随机数安全
- 每次加密/签名必须使用不同的随机数k,否则会泄露私钥
- 必须使用国家认证的随机数发生器
3. 参数规范
- 必须使用国密指定的椭圆曲线参数,禁止自定义曲线
- 金融、政务场景需通过国家密码管理局的合规性测试
4. 格式处理
- SM2密文格式通常为C1C3C2(国密标准)或C1C2C3(部分js库使用)
- 前后端需要统一密文格式,避免加解密失败
5. 性能优化
- 建议对敏感接口(登录、支付、修改密码等)全部启用双向SM2
- 签名建议只签业务关键字段,防止重放攻击仍需配合timestamp + nonce
七、总结
SM2算法作为中国自主研发的密码算法,在安全性、效率和自主可控性方面具有显著优势。通过SpringBoot集成SM2,可以快速构建符合国密标准的安全应用系统。在实际项目中,需要重点关注密钥管理、随机数安全、参数规范等关键点,确保系统的安全性和合规性。
随着《密码法》的实施和信创产业的推进,SM2算法将在更多关键领域替代RSA等国际算法,成为数字中国建设的重要安全基石。