2. 常见国密实现库对比:OpenSSL、GmSSL、Bouncy Castle、腾讯Kona等

做国密改造这几年,我接触过不少团队。大家上来就问:“哪个库最好?”

说实话,没有“最好”的库,只有“最合适”的。你想想看,一个嵌入式设备和一台金融服务器,对库的要求能一样吗?

这一节,我把市面上主流的几个国密实现库掰开揉碎讲清楚。哪些坑我踩过,哪些库看起来很美但实际用起来想骂人,我都会说。

2.1 四巨头速览

目前国内国密改造用得最多的,就是下面这四个库。我按出身和定位排了个序:

库名称 维护方 核心语言 国密支持范围 许可证
OpenSSL OpenSSL社区 C SM2/SM3/SM4(需补丁或3.x+) Apache 2.0
GmSSL 北京大学 C 全栈国密(SM2/3/4/9,含ZUC) Apache 2.0
Bouncy Castle Legion of the Bouncy Castle Java/C# SM2/SM3/SM4(BC 1.60+) MIT
腾讯Kona 腾讯 Java SM2/SM3/SM4(含国密TLS) BSD 2-Clause
我的建议: 选库之前,先搞清楚你的运行环境。C/C++项目首选OpenSSL或GmSSL;Java项目优先看Bouncy Castle和Kona。别在Java里硬塞一个JNI调C库,维护成本会让你哭。

2.2 OpenSSL:老大哥的国密之路

OpenSSL 3.x开始原生支持SM2/SM3/SM4。这是个好消息,但别高兴太早。

我在2022年帮一家银行做TLS国密改造时,用的就是OpenSSL 3.0。当时发现一个问题:SM2签名验签的性能,比RSA 2048慢了将近3倍。后来查了源码才发现,OpenSSL的SM2实现走的是通用椭圆曲线路径,没有针对SM2的p和a参数做优化。

核心优缺点:
  • 优点: 生态最成熟,文档最多,社区活跃。如果你已经在用OpenSSL做国际算法,切国密的学习成本最低。
  • 缺点: 国密性能不是最优;SM2签名验签的侧信道防护不够完善;3.x版本API变化大,从1.x迁移要改不少代码。
避坑指南: 我曾经遇到一个项目,直接用OpenSSL 1.1.1打国密补丁。结果补丁和主线代码冲突,编译出来的库在ARM平台上跑SM4 CBC解密时,偶尔会出段错误。后来全部切到GmSSL才稳定。如果你必须用OpenSSL,建议直接上3.x,别打补丁。

2.3 GmSSL:国密原生的选择

GmSSL是北大关振胜老师团队维护的。说白了,这就是为国密而生的库。

它的优势很明显:SM2/SM3/SM4/SM9/ZUC全支持,而且实现上参考了国标的最新修订版。我记得2021年国密局更新了SM2的密钥派生函数规范,GmSSL两周内就跟进了。OpenSSL那边等了半年。

对比维度 GmSSL OpenSSL 3.x
SM2签名性能(ops/s) ~3200 ~2100
SM4-CBC吞吐(MB/s) ~580 ~490
国密TLS 1.3支持 原生支持 需额外配置
API稳定性 中等(版本间有break change) 高
个人经验: 如果你做的是纯国密项目,比如政务内网、金融加密机,直接上GmSSL。它的SM2签名验签实现用了优化的Montgomery模乘,性能比OpenSSL好一截。但要注意,GmSSL的API风格和OpenSSL不太一样,迁移时别想当然。

2.4 Bouncy Castle:Java生态的守门员

Java开发者对Bouncy Castle应该不陌生。它从1.60版本开始支持SM2/SM3/SM4,目前已经是Java国密实现的事实标准。

不过,BC有个老毛病:它的SM2实现默认用的是未压缩公钥格式。国密标准里推荐的是压缩格式。我去年帮一个支付公司做审计时,发现他们用BC生成的SM2公钥长度是65字节(未压缩),而对接的银行网关只认33字节(压缩)。两边扯了三天皮。

选型要点:
  • 优点: Java生态兼容性最好;支持JCA/JCE标准接口;SM3/SM4实现经过大量生产验证。
  • 缺点: SM2性能一般(纯Java实现,没有JNI加速);国密TLS支持需要额外依赖(BCJSSE);公钥格式默认不兼容国标。
避坑指南: 我曾经在Spring Boot项目里用BC做SM2签名,上线后发现CPU飙升。一查,BC的SM2签名每次都会重新生成随机数k,而Java的SecureRandom在Linux上默认用/dev/random,高并发时阻塞了。解决方案:显式指定NativePRNGNonBlocking算法。

2.5 腾讯Kona:云原生国密新势力

Kona是腾讯开源的国密Java实现,基于OpenJDK的Security Provider机制。它的最大亮点是国密TLS 1.3支持,而且性能调得不错。

我测试过Kona的SM2签名,在同等硬件条件下比BC快了约40%。原因很简单:Kona用了Java 11的Vector API做SM3哈希加速,而BC还在用纯标量实现。

适用场景:
  • 腾讯云生态内的项目(Kona和腾讯的密钥管理服务集成度很高)
  • 需要国密TLS 1.3双向认证的Java微服务
  • 对SM2签名性能有较高要求的场景

但Kona也有短板:社区规模远不如BC,遇到问题百度都搜不到几个结果。而且它只支持Java 11+,老项目升级成本高。

2.6 选型决策框架

说了这么多,到底怎么选?我画了一张决策图,你对着走就行:

国密实现库选型决策树 你的运行环境? C/C++ 项目 Java 项目 纯国密场景 → GmSSL 混合算法场景 → OpenSSL 3.x Java 8 / 老项目 → Bouncy Castle Java 11+ / 云原生 → 腾讯Kona 选型补充说明 • 需要国密TLS 1.3?C/C++选GmSSL,Java选Kona • 需要SM9标识密码?目前只有GmSSL支持 • 需要FIPS 140-2认证?OpenSSL有FIPS模块,其他库没有 • 嵌入式/低资源设备?GmSSL裁剪后最小约200KB,OpenSSL约500KB • 团队技术栈:熟悉OpenSSL API的团队,迁移到GmSSL成本较低

2.7 我的最终建议

选库这件事,没有银弹。我个人的习惯是:

  • 新项目、纯国密、C/C++: 闭眼选GmSSL。性能好,合规省心。
  • 已有OpenSSL基础设施、需要混用国际算法: 升级到OpenSSL 3.x,别打补丁。
  • Java 8项目、团队对BC熟悉: 继续用Bouncy Castle,但注意公钥格式和随机数问题。
  • Java 11+、云原生、需要国密TLS: 试试腾讯Kona,性能确实香。
最后提醒一句: 不管你选哪个库,上线前一定要做国密合规性测试。我见过不止一个项目,用GmSSL跑SM2签名,结果密钥对生成时没用国标指定的随机数种子,商密评审直接打回。库本身没问题,但用错了API,照样不合规。