开源之夏-21
今天必须开始SKF(Smart Key Function Interface/智能密码钥匙功能接口)部分了。需要先整理一下SDF/SKF的业务场景差异,对应硬件设备,现有实现思路。
SDF(Server Development Framework)和这份文件里提到的“智能密码钥匙接口”虽然都提供密码服务,但它们的应用场景、接口定位以及对应的硬件设备是完全不同的两条线。下面用一句话先给你区别,再逐个展开。
一句话区分
SDF面向的是“机房里的高速密码模块”,这份文件面向的是“每个人手里的U-key/USBKey”。
一、应用场景与定位
这里提到的接口(国密 SKF 接口族)
• 场景:PC、移动终端上的应用需要调用“个人持有的智能密码钥匙”里的密钥做签名、解密、身份认证等。
• 定位:把 U-key 这一“小型密码设备”抽象成一个统一的本地设备接口,供浏览器、Office、VPN 客户端等直接调用。SDF(GMT 0018《密码设备应用接口规范》)
• 场景:服务器、安全网关、签名验签服务器、SSL 卸载设备等需要高速、高并发密码运算。
• 定位:为“机房级密码模块/密码卡”定义的标准 API,供操作系统内核、中间件、Web 服务器、数据库加密引擎等调用。
二、对应的硬件设备名称
这份文件指向的设备
• 典型名称:智能密码钥匙、USBKey、U-key、国密 Key、二代 Key、蓝牙 Key、音频 Key 等。
• 形态:USB-A/C、蓝牙、NFC、Lightning、Type-C 各种“小钥匙”或“小U盘”。SDF 指向的设备
• 典型名称:密码卡(PCI-E 密码卡)、服务器密码机、SSL 加速卡、签名验签服务器、高速 HSM(Hardware Security Module)等。
• 形态:插在服务器主板上的 PCI-E 卡、1U/2U 机架式独立设备、刀片式模块等。
三、总结对照表
维度 | 本文件接口(SKF 族) | SDF 接口(GMT 0018) |
---|---|---|
面向场景 | 个人终端、PC、移动设备 | 服务器、数据中心、网关、云平台 |
接口使用者 | 浏览器、VPN 客户端、桌面应用 | 操作系统、中间件、数据库、Web 服务器 |
典型硬件名称 | USBKey / 智能密码钥匙 / U-key | 密码卡 / 服务器密码机 / HSM |
性能要求 | 低并发、低功耗、便携 | 高并发、高速、7×24 连续运算 |
国密标准编号 | GMT 0016-2012(SKF 族) | GMT 0018-2012(SDF 族) |
一句话再总结
你手里插的那个“小U盘”叫智能密码钥匙,走 SKF 接口;
机房里那块像显卡一样的“密码卡”或 1U 机架盒子,走 SDF 接口。
GmSSL为什么要用engine提供对SKF的支持,而SDF没有集成到provider/engine?
GmSSL 把 SKF 做进 ENGINE,却把 SDF 留在“外面”的根本原因可以归结为一句话:
SKF 设备必须由“用户态应用”直接驱动,SDF 设备则天然由“内核或独立服务”驱动,两者在部署模型、调用路径和生命周期管理上完全不同。
下面按三条主线把原因拆开。
一、部署模型:谁负责“打开”设备
SKF(U-key、USBKey)
• 设备插在终端上,进程一启动就要枚举、认证、打开。
• 认证口令、PIN 码、设备认证密钥都在应用进程内部流转。
⇒ 必须让应用自己调用SKF_OpenDevice
、SKF_AuthDev
等函数。
⇒ 用 ENGINE 把这一整套流程封装成 OpenSSL/GmSSL 的 EVP 钩子,最省事。SDF(PCI-E 密码卡、服务器密码机)
• 设备在机房,通常只在系统启动时由 root 做一次初始化。
• 之后普通业务进程通过内核驱动或独立守护进程拿到“会话句柄”即可。
⇒ 调用链是:业务 → GmSSL → 内核 ioctl / Unix Socket / RPC → 硬件。
⇒ 这套逻辑跟 OpenSSL ENGINE 的“把算法钩子直接指向用户态 so”不匹配,所以 GmSSL 把它做成独立动态库(libsdf.so
)或配置驱动而不是 ENGINE。
二、证书/密钥可见性
- SKF:密钥和证书都在 USBKey 里,必须靠应用把它“读出来”或“把摘要送进去”。ENGINE 可以统一完成这两件事。
- SDF:证书通常是文件系统里的 PEM/CRT,或者由密码机内部的“对象管理器”统一维护。业务进程不需要(也做不到)把证书从卡里导出,因此不需要 ENGINE 去插手证书加载流程。
三、性能与并发
- SKF 设备低并发,ENGINE 里做阻塞调用即可。
- SDF 设备高并发,需要:
– 会话池复用
– 多进程/线程安全
– 零拷贝 DMA
这些要求更适合在内核模块或独立服务里解决。GmSSL 只要提供“把运算请求转发到该服务”的最小 glue 代码即可,塞进 ENGINE 反而把层次搞乱。
一句话总结
SKF 设备“长在应用旁边”,用 ENGINE 能让 GmSSL 直接握到它;
SDF 设备“长在系统深处”,GmSSL 只需把运算指令递过去,没必要、也不适合再走 ENGINE。
那provider呢?SDF后边可以用provider支持吗?
可以,但要分清“能不能”和“应不应该”两码事。
OpenSSL 3.x 的 Provider 体系在技术上允许把任何算法/设备接入,包括 SDF;GmSSL 也同步了这套接口。真正问题是:把 SDF 做进 provider 以后,谁来维护会话句柄、谁跑守护进程、谁负责并发,这些工作量并不会因为换了 provider 就消失。下面把可行做法、已有案例和坑一次说清。
一、技术可行性
- Provider 只是“算法钩子”的另一种实现方式,跟 ENGINE 逻辑类似,但
• 接口更细(可以只挂一个算法,也可以挂整个 dispatch table)
• 支持热插拔、可组合、可并行加载多个 provider - 因此理论上可以把 SDF 的
SDF_OpenSession
、SDF_Encrypt
等函数封装成一个libsdf-provider.so
,在配置里用OPENSSL_CONF
或OSSL_PROVIDER_load()
动态加载即可。
二、已有实践
- 国内几家 HSM 厂商(江南科友、三未信安、卫士通)已提供 SDF-provider 原型:
– 把会话池、多线程锁、句柄缓存都做到 provider 内部;
– 对外暴露标准的 EVP_CIPHER、EVP_PKEY_METHOD;
– 配置示例:– 启动后1
2
3
4
5
6
7[provider_sect]
default = default_sect
sdf = sdf_sect
[sdf_sect]
module = /opt/hsm/lib/libsdf-provider.so
init = sdf_provider_initopenssl list -providers
能看到SDF Provider
条目。
三、需要解决的三大坑
- 会话生命周期管理
- provider 里要自己维护“设备句柄池”——不能像 ENGINE 那样简单地把
SDF_OpenSession
直接映射成EVP_PKEY_CTX_new()
,否则会话耗尽。
- provider 里要自己维护“设备句柄池”——不能像 ENGINE 那样简单地把
- 跨进程/线程安全
- 密码卡驱动通常只允许一个进程打开有限个数设备句柄;provider 必须加引用计数、死锁检测。
- 配置/部署复杂度
- provider 仍然需要 root 权限做一次设备初始化(
SDF_OpenDevice
),之后普通用户才能用。 - 如果把它做成 systemd 守护进程,则 provider 退化成“客户端 stub”,又回到了“独立服务”模式——跟现在用独立的
sdf_engine
或 RPC 方式并无本质区别。
- provider 仍然需要 root 权限做一次设备初始化(
一句话结论
技术上完全可以把 SDF 设备做成 provider;
但它不是“把 ENGINE 代码直接搬到 provider 目录”那么简单,而是要额外写一套会话池、并发控制和守护进程逻辑。
所以目前主流做法仍是:
- 个人 USBKey → SKF-provider(已有,简单易用)
- 机房密码卡/服务器密码机 → 继续用独立 SDK、内核驱动或 RPC 服务,而不是急着塞进 provider。
我注意到SKF有一些非常细化的设备管理函数,为什么SDF没有这部分?
一句话解释:
SDF 标准把“设备管理”全部交给了操作系统或厂商驱动去做,标准本身只管“密码运算”。
为什么 SDF 没有这些函数?
维度 | SKF | SDF |
---|---|---|
定位 | 密码设备通用接口(U-Key、智能卡、USB Token) | 高性能密码模块接口(PCI-E 算法卡、服务器 HSM) |
典型形态 | 可热插拔的外设 | 固定在机箱内的板卡或机架设备 |
使用场景 | 桌面用户随时插拔 | 机房长期在线,开机即可用 |
设备管理需求 | 需要枚举、热插拔、事件通知 | 不需要:系统启动时由驱动/内核加载,应用只关心“打开会话” |
标准范围 | 把“设备生命周期”纳入接口 | 把“设备生命周期”留给操作系统或厂商工具 |
举例对比
- SKF:用户把 U-Key 插进电脑 → 应用调用
SKF_WaitForDevEvent
感知 →SKF_EnumDev
枚举 →SKF_ConnectDev
建立连接。 - SDF:服务器上电后,驱动自动把算法卡注册成
/dev/sdf0
→ 应用只需要SDF_OpenDevice("/dev/sdf0")
,没有插拔、枚举、事件一说。
结论
SDF 的设计假设设备一直在线、固定不动,因此把设备管理下沉到驱动/操作系统/厂商工具,标准本身不再重复定义。
SKF为什么要提供密码服务?,它不是智能密码卡吗?只管认证就行吧?智能在哪?
一句话:
在 SKF 的世界里,那张“卡”本身就是一台袖珍密码机,不仅要“认证”,还要独立完成全套密码运算,所以接口里必须自带所有算法能力。
1. SKF 的“智能”到底指什么?
维度 | 普通存储卡/口令卡 | SKF 智能密码卡 |
---|---|---|
CPU & 存储 | 无/极弱 | 带安全芯片、EEPROM、真随机数发生器 |
算法执行 | 只做身份比对 | 内部硬件执行 RSA/SM2/SM3/SM4… |
密钥存放 | 明文或可导出 | 私钥永不出卡,运算都在卡内 |
典型用途 | 门禁、SIM PIN | U-Key、网银盾、电子签章、VPN 证书 |
因此,“智能”体现在卡里有完整密码协处理器,而不是“只存口令”。
2. 为什么接口里必须包含全部密码服务?
安全模型需要
私钥一旦离开卡体,安全性就降到软件级;所以加密、签名、协商会话密钥都要在卡内完成。桌面/移动端场景
用户电脑或手机算力有限,且希望“插上就用”,于是把整套算法搬进卡里,即插即算。合规要求
国密规范把 SKF 定义为“通用密码设备接口”,必须覆盖所有国密算法,才能通过检测、拿到销售许可。
3. 一句话总结
SKF 的“智能”不是会认人,而是自带一整套国密算法的安全 SoC;
因此接口必须提供 完整的密码服务,才能让用户“插卡即用”,私钥永不落地。
SoC = System on Chip(片上系统)
在 SKF 智能密码卡里,SoC 就是把下面所有东西都做到同一块芯片里:
- CPU(安全核,通常是 32 位 RISC)
- 存储器(ROM、RAM、EEPROM / Flash)
- 国密算法加速器(SM2、SM3、SM4、RSA)
- 真随机数发生器(TRNG)
- 接口控制器(USB、ISO7816、SPI 等)
- 安全传感器(电压、温度、光检测,防物理攻击)
于是这张卡看起来只是“U-Key”,实际上是一台完整的微型计算机,所以叫 SoC。
U盾也是这样的吗?还是只带密钥
是的,U 盾(USBKey)并不是“只带密钥的存储器”,而是一颗完整的 SoC(System on Chip)。
根据权威拆解和官方文档,典型 U 盾内部包括:
- CPU(8/32 位安全微控制器)
- ROM(固化的 COS/算法)
- RAM(运行时内存)
- EEPROM/Flash(证书、私钥、文件系统)
- 真随机数发生器(TRNG)
- 国密 & RSA/ECC 协处理器
- I/O 控制器(USB、ISO7816 或 SPI)
因此,U 盾同样是一台袖珍密码机:密钥在芯片内生成、存储且永不导出,所有加解密、签名运算都在芯片内部完成。
这与 PCI-E 形态的 SDF 算法卡本质相同,只是封装成了“U 盘”大小,方便用户随身携带、即插即用。
U盾和SKF的最大区别?
U 盾 ≈ “USB 形态的 SKF 设备”,二者在硬件组成上几乎没有区别;真正拉开差距的是规范定位、接口粒度、使用场景和认证体系。
维度 | U 盾(USBKey) | SKF(国密智能密码钥匙) |
---|---|---|
规范归属 | 银行/行业通用叫法,通常遵循 SKF 国标 | 国标 GM/T 0016~0018 的正式名称 |
接口粒度 | 为了快速集成,厂商往往再包一层精简 API | 必须实现 GB 里列出的 全套 70+ 条函数 |
认证体系 | 各家银行/CA 自行做准入测试 | 必须通过 国家密码管理局的 SKF 检测,拿型号证书 |
使用场景 | 网银、电子政务、手机盾,即插即走 | 同上,但强调 跨平台通用性(Windows/Linux/Android/iOS) |
形态 | USB-A、Type-C、蓝牙、NFC 皆可 | 同样形态,只是名字更“官方” |
所以:
- U 盾 ≈ 一个商业品牌/场景包装;SKF = 技术规范 + 合规认证。
- 市面买到的 U 盾,90 % 以上内部就是 SKF 芯片,只是对外宣传叫法不同 。
除了GM/T 0016是SKF接口规范,还需要GM/T 0017也是SKF接口规范。
观察SKF系统架构图,还有一层:智能密码钥匙密码应用接口数据格式。
这一层(“智能密码钥匙密码应用接口数据格式”)是把“函数调用”翻译成“字节流”的协议层。
作用一句话:让“应用进程”和“USB/蓝牙/NFC 设备”能互相听懂对方的语言。
1. 它解决什么问题?
- 应用层只认识 C 函数:
SKF_Encrypt(...)
- USB/NFC/蓝牙链路只认字节流(APDU、TLV、帧头帧尾、CRC…)
于是需要:
“接口数据格式层” = 把 C 参数 → 字节流 → 发给设备 → 把设备返回的字节流 → 解析成 C 结构体/返回值
2. 具体职责
任务 | 举例 |
---|---|
序列化 | 把 SKF_Encrypt 的参数(算法 ID、密钥句柄、明文长度…)压成 1 条 APDU 或 TLV 报文 |
分片/重组 | 明文 > 64 k 时,切成多块,按协议序号重拼 |
错误码映射 | 设备返回 0x6A 88 → 映射成 SKF_ERR_KEY_NOT_FOUND |
重试/超时 | USB 丢包或蓝牙断链,按协议重发 |
多设备并发 | 通过 SessionID/SlotID 在字节流里区分设备 1、2、n |
3. 一句话总结
“接口数据格式层”就是 SKF 协议栈里的“翻译官”,
把高层 C 函数翻译成设备能识别的字节协议,再把设备回包翻译成应用能用的 C 结果。
(已经郁郁了,,,)