SDFP:基于 openHiTLS Provider 接口的 SDF 适配实现项目

openHiTLS SDF Provider

分支1Tags0
文件最后提交记录最后更新时间
28 天前
1 个月前
28 天前
1 个月前
1 个月前
10 个月前
28 天前

SDFProv (sdf_provider)

新增能力(SM3/SM4/SM4-GCM)

  • 哈希:SM3(HASH OP),通过 SDF HashInit/Update/Final 实现。
  • 对称加解密:SM4 支持 ECB、CBC、GCM 三种模式:
    • 原始密钥:Init 直接传入 16 字节密钥,内部调用 SDF_ImportKey + Encrypt/DecryptInit。
    • KEK 路径(仅限 ECB/CBC):通过 CRYPT_CTRL_SET_KEK_ID 设置非 0 KEK 索引并使用 SDF_ImportKeyWithKEK 导入会话句柄。
    • CBC 需 16 字节 IV;ECB 无 IV;GCM 需 12 字节 Nonce。
    • CRYPT_CTRL_REINIT_STATUS 可在持有句柄时重置链路状态(可携带新 IV)。
  • SM4-GCM(AEAD):
    • 底层调用 SDF_AuthEncInit/Update/FinalSDF_AuthDecInit/Update/Final
    • 加密调用顺序InitCtxCRYPT_CTRL_SET_TAGLENCRYPT_CTRL_SET_AADUpdateFinalCRYPT_CTRL_GET_TAG
    • 解密调用要求InitCtx 后、首次 Update / Final 前完成 CRYPT_CTRL_SET_AAD(如有 AAD)和 CRYPT_CTRL_SET_TAG(缓存期望 Tag 及其长度),两者顺序不限;随后 UpdateFinal(SDF 设备内部验 Tag)
    • Tag 长度默认是 0,表示未设置,开始 GCM 加解密时会报错;SDFP 本地仅允许 32 bit、64 bit,以及 96 到 128 bit 间 8 的倍数长度 Tag(对应 4/8/12/13/14/15/16 字节)。

新增 demo

  • sm3_hash: 计算 "abc" 的 SM3 摘要并校验标准向量。
  • sm4_ecb: SM4-ECB 以固定向量加解密回环并对比标准密文。
  • sm4_cbc: RAW 密钥 CBC 交叉验证(CBC 无填充)。
  • sm4_kek_cmd_cross: external provider 下通过 CRYPT_CTRL_SET_KEK_ID 设置 KEK index,执行 SM4 ECB/CBC KEK 交叉验证,并校验 KEK index 0 会被拒绝。
  • sm4_internal_kek_cross: internal provider load 参数带入 SM4 KEK index,执行 SM4 ECB/CBC KEK 交叉验证。
  • sm4_gcm: SM4-GCM 加密取 Tag,再带 Tag 解密验证,输出明文与原文对比。 (均依赖环境变量 SDF_LIB_PATH;SM2 internal 用例需显式设置 SDF_ECC_KEY_INDEXSDF_ECC_KEY_PASS;SM4 KEK 用例需显式设置非 0 SDF_SM4_KEY_INDEX;从当前目录加载 libSDFProv.so

基于 openHiTLS Provider 接口的 SDF 适配实现。
当前仓库输出的 Provider 名称为 SDFProv(对应 provider=SDFProv)。

能力范围

根据 src/ 下当前实现,已注册能力如下:

  • SM2: 密钥管理(KeyMgmt)、签名/验签(Sign)、非对称加解密(AsymCipher)、密钥交换(KeyExch)
  • RSA: 密钥管理(KeyMgmt)、签名/验签(Sign)、非对称加解密(AsymCipher)
  • SM3: 哈希摘要(Hash)
  • SM4: ECB、CBC、GCM(AEAD)对称加解密(SymmCipher)

注:非对称算法支持外部明文密钥、当次生成的运行时密钥,以及通过索引访问的 SDF 内部密钥;内部私钥访问必须显式配置口令。

目录结构

  • include/: Provider 对外公共头文件(sdfp.h, sdfp_errno.h
  • src/: Provider 源码,包含 common、sm2、sm3、sm4、rsa 模块
  • demo/: 示例程序(sm2_signsm2_encryptrsa_signrsa_encryptsm3_hashsm4_testsm4_gcm
  • CMakeLists.txt: 构建脚本

依赖

  • CMake >= 3.10
  • openHiTLS 头文件与依赖库(libhitls_bsl.solibhitls_crypto.so
  • SDF 标准接口头文件:仓库内已在 src/common/ 维护一份内部标准头文件,无需额外传入 SDF SDK 头目录
  • Linux dlopen 运行时(链接 dl

构建参数

CMakeLists.txt 目前支持以下参数:

  • HITLS_DIR: openHiTLS 安装目录(内部使用 includelibbuild 下的动态库)
  • SDF_INCLUDE_DIR: 可选,厂商 SDF 头文件目录;设置后优先于仓库内标准头
  • SDF_DIR: 可选,若设置且未设置 SDF_INCLUDE_DIR,则使用 ${SDF_DIR}/include
  • BUILD_DEMOS: 是否构建 demo,默认 ON
  • SDFP_DEBUG: 是否开启 provider 调试日志,默认 OFF;开启后 SDFP_LOG 会向 stderr 输出函数名、行号和错误码

说明:本项目编译期不链接 SDF 动态库,而是在 Provider 初始化时通过显式 SDFP_PARAM_SDF_LIB_PATH 参数使用 dlopen 加载真实设备库。demo 会从 SDF_LIB_PATH 读取路径并作为该参数传入 Provider。因此 SDF_LIB_DIRSDF_NAME 不再是构建必需参数。

构建

mkdir -p build
cd build
cmake .. \
  -DHITLS_DIR=/path/to/hitls \
  -DSDFP_DEBUG=ON \
  -DBUILD_DEMOS=ON
make -j

如果真实设备 SDK 的类型定义或算法 ID 与仓库维护的标准头不同,可显式覆盖:

cmake .. \
  -DSDF_INCLUDE_DIR=/path/to/vendor/sdf/include \
  -DHITLS_DIR=/path/to/hitls \
  -DBUILD_DEMOS=ON
make -j

测试与示例运行

构建完成后可在 build/ 目录执行:

ctest --output-on-failure

或手动运行:

export SDF_LIB_PATH=/path/to/libsdf.so
export SDF_ECC_KEY_INDEX=your-ecc-key-index
export SDF_ECC_KEY_PASS=your-ecc-private-key-password
export SDF_SM4_KEY_INDEX=your-sm4-kek-index
./sdfp_demo

预期成功输出:

===== External Provider Tests =====
===== SM3 Hash =====
PASS: sm3_hash

===== SM4 ECB =====
PASS: sm4_ecb

===== SM4 CBC =====
PASS: sm4_cbc

===== SM4 GCM =====
PASS: sm4_gcm

===== SM2 Encrypt =====
PASS: sm2_encrypt

===== SM2 Sign =====
PASS: sm2_sign

........

===== Result: 14/14 passed =====

运行前提与注意事项

  • demo 会分两次加载 Provider:external 用例只传 SDF_LIB_PATH,不传 ECC/SM4 index/password;external 分组中的 cmd 用例会在 ctx 上显式设置 SM2 index/password 和 SM4 KEK index。internal 用例卸载后重新加载,并按环境变量传 SDF_ECC_KEY_INDEX / SDF_ECC_KEY_PASS / SDF_SM4_KEY_INDEX / SDF_SM4_KEY_PASS。internal 分组也会跑普通 SM2 external key 用例,确认显式设置/生成的外部密钥不会被 provider 默认 internal index 覆盖。 完整 demo 需要显式传入 SDF_ECC_KEY_INDEXSDF_ECC_KEY_PASS 和非 0 SDF_SM4_KEY_INDEX;demo 不提供默认索引或默认私钥访问口令。

  • demo 首次加载时通过 CRYPT_EAL_ProviderSetLoadPath(NULL, "./") 从当前目录加载 Provider,因此应在 build/ 目录运行,保证能找到 libSDFProv.so

  • SDF 动态库路径是通过 SDFP_PARAM_SDF_LIB_PATH(ID=102)参数传递给 CRYPT_EAL_ProviderLoad 的;未传会返回 SDFP_ERR_NULL_INPUT

  • SM2/RSA:keyIndex == 0 表示没有内部密钥索引,走 external 明文密钥路径;keyIndex != 0 表示走 SDF internal key 路径。internal 私钥操作必须配置 password,否则返回缺口令错误;单独设置 password 不会让 keyIndex == 0 的 ctx 切到 internal。

  • SM4 ECB/CBC:CRYPT_CTRL_SET_KEK_ID 是 KEK/internal 模式选择命令,参数必须是非 0 KEK index;传 0 会返回 CRYPT_INVALID_ARG。raw key external 路径不要调用该命令。SM4 不使用 CRYPT_CTRL_KEY_PASS;KEK 访问口令仅来自 provider load 参数 SDFP_PARAM_SM4_KEY_PASS

Provider 参数(当前实现)

对外加载参数定义在 include/sdfp.h

  • SDFP_PARAM_SDF_LIB_PATH (102): SDF 动态库路径(Provider 初始化必需)
  • SDFP_PARAM_ECC_KEY_INDEX (200): ECC 内部密钥索引默认值,0 表示未设置
  • SDFP_PARAM_ECC_KEY_PASS (201): ECC 内部私钥访问口令
  • SDFP_PARAM_SM4_KEY_INDEX (202): SM4 KEK 索引默认值,0 表示未设置
  • SDFP_PARAM_SM4_KEY_PASS (203): SM4 密钥口令(预留给需要口令保护 SM4 密钥的 SDF 实现)

未设置 ECC 口令时,ECC 内部私钥访问操作会失败,不再回退到内置默认口令。设置 SDFP_PARAM_SM4_KEY_PASS 时,会在支持 SDF_GetKEKAccessRight / SDF_ReleaseKEKAccessRight 的 SDF 实现上执行 KEK 访问授权。

Provider-specific 控制参数定义在 include/sdfp.h

  • CRYPT_CTRL_KEY_INDEX (101): 内部密钥索引
  • CRYPT_CTRL_KEY_USAGE (103): 密钥用途
  • CRYPT_CTRL_GET_KEY_INDEX (104): 获取密钥索引
  • CRYPT_CTRL_GET_KEY_USAGE (105): 获取密钥用途
  • CRYPT_CTRL_KEY_PASS (106): 设置私钥口令
  • CRYPT_CTRL_SET_KEK_ID (110): 设置 KEK 索引(SM4 KEK 模式)
  • CRYPT_CTRL_GEN_DEK_WITH_KEK (111): 通过 KEK 生成会话密钥,可取回密文
  • KEY_USAGE_SIGN / KEY_USAGE_ENC / KEY_USAGE_EXCH: 内部密钥用途
  • CRYPT_CTRL_REINIT_STATUS: openHiTLS 重置对称密码上下文状态命令(可带新 IV)

License

LICENSE