开源之夏01:项目启动与OpenSSL入门

我参加了今年的开源之夏项目,负责完成:铜锁密码库支持密码设备接口(SDF)和智能密码钥匙接口(SKF)功能。这是一次很好的机会去提升自己解决问题的能力,同时也获得了和开源前辈们交流的机会。

项目概述

铜锁/Tongsuo 是一个提供现代密码学算法和安全通信协议的开源基础密码库,为存储、网络、密钥管理、隐私计算等场景提供底层密码学基础能力。它于 2019 年从 OpenSSL 1.1.1 fork,2022 年更名为 Tongsuo 并捐赠给开放原子开源基金会。

项目产出要求:

  1. 完善 Tongsuo 中的 SDF 功能:开发完整 SDF 接口,至少适配一种密码卡设备,提供完善的测试用例和文档
  2. 开发 SKF 接口:开发完整 SKF 功能接口,至少适配一种智能密码钥匙设备,提供完善的测试用例和文档

密码设备应用接口规范(GM/T 0018-2023)定义了密码卡设备的调用接口;智能密码钥匙接口规范(GM/T 0016-2023)定义了智能密码钥匙设备的调用接口。目前 Tongsuo 只支持部分 SDF 接口,还不支持 SKF 接口。

第一阶段:环境搭建与初次交流

第一周主要完成了 Windows 11 和 Ubuntu 22.04 WSL 的开发环境配置。尝试编译了 SDF 相关代码,但因缺少 sdfe_api.h 头文件导致编译失败。同时成功运行了 sm_test 示例程序,分析了 SDF 目录下的文件结构和功能——接口框架是完整的,但实际算法实现和硬件支持尚未完成。

7月11日与 k1 老师开腾讯会议了解项目情况。老师指出 sdfe_api.h 头文件缺失是正常的,因为没有硬件。眼下需要先确定硬件才能开展,可以看到相关接口已经搭好,等待填充。

老师带我总览了项目结构,介绍了铜锁目前在做的工作和未来的发展方向。铜锁作为从 OpenSSL fork 的库,结构非常相似,因此可以同时参考 GmSSL 和 OpenSSL,三者相互参照。老师还特别提到了 engines/ 文件夹——后来学 OpenSSL 时才明白老师用意:如果你在研究”怎么让 OpenSSL 跑在国产密码卡上”或”如何用 Intel QAT 把 TLS 握手加速 5 倍”,八成都会先摸进 engines/ 找灵感。

7月19日与肖老师通电话确认项目进展。确定了最终交付目标:SDF 命令行应用、SKF 命令行应用、SDF API 适配、SKF API 适配(真实硬件编译、全功能测试),以及待定的软件模拟 SDF/SKF 引擎。

第二周聚焦于铜锁的安装、命令行工具的使用以及基于铜锁 C 库的小程序开发。深入理解了铜锁的安装原理——通过 Perl 脚本生成 make 文件、配置文件的生成,以及 make 和 make install 的执行过程。解决了因 OpenSSL 库版本不匹配导致的报错,通过配置环境变量让系统优先加载铜锁自带的库。用铜锁 C 库实现了一个 AES-256-CBC 加解密小程序并成功运行,验证了其与 OpenSSL 相似的 API 用法。

OpenSSL 环境准备

Windows 环境

需要的工具链:VS2022、Perl5、NASM(汇编器)。

1
2
3
4
# 打开 x86 Native Tools Command Prompt
perl Configure VC-WIN32
nmake
nmake install

用 dumpbin /Headers <文件名> 识别库是 32 位还是 64 位。

Linux 环境常见问题

OpenSSL 默认安装到 /usr/local/lib64,但可执行文件从 /usr/lib64 读取链接库,导致 error while loading shared libraries: libcrypto.so。四种解决方案:

  1. 临时:export LD_LIBRARY_PATH=/usr/local/lib64:$LD_LIBRARY_PATH
  2. 永久:编辑 /etc/ld.so.conf,增加 /usr/local/lib64,执行 ldconfig -v
  3. 软链接到 /usr/lib64
  4. 修改 Makefile 中的 LIBDIR 重新安装

静态库编译:gcc demo.c <静态库路径> -ldl -lpthread -o static_demo.out

OpenSSL 源码结构

  • crypto/:核心代码(占 80% 以上),包含所有算法实现
  • apps/:命令行工具源码,生成 openssl.exe
  • engines/:加密引擎,可替换为硬件加速卡(Intel QAT、国密卡等)
  • demos/:示例代码
  • include/:头文件
  • test/:单元测试
  • 三处配置入口:Configurations/、config、Configure

OpenSSL 密码学 API 入门

Base64 编解码与 BIO 接口

Base64 是二进制到字符串的转换工具,应用场景包括邮件编码、XML/JSON 存储二进制、URL 数据传递、数据库文本存储等。

编码原理:将 3 个 8 位字节(24 位)转化为 4 个 6 位字节,每个 6 位前补两个 0 形成 8 位字节。不足 3 字节时用 0 填充,输出用 = 补足。

OpenSSL 的 BIO 接口 提供了统一的 I/O 抽象,包括 6 种 filter 型和 8 种 source/sink 型。BIO 链通常由一个 source BIO 和一个或多个 filter BIO 组成:

  • BIO_new(BIO_s_mem()):创建内存数据源
  • BIO_new(BIO_f_base64()):创建 Base64 过滤器
  • BIO_push(b64_bio, mem_bio):形成 BIO 链
  • BIO_write/BIO_read_ex:写编码/读解码
  • BIO_FLAGS_BASE64_NO_NL:禁止自动换行

为什么走字节流而不是直接编码数字? 因为国际标准(如 ASN.1/DER、SDF、PKCS#1)都规定敏感数据必须用二进制格式,保证互操作性和安全。流程是:BIGNUM → 字节流(BN_bn2bin)→ Base64 编码 → 字符串。

此外还有 Base16(4 位→1 字符,大小翻倍)和 Base58(去掉易混淆字符 0/O/l/I/+ / /,用于比特币地址)。

单向散列函数

OpenSSL 推荐使用 EVP 接口 替代旧版 API(如 MD5_Init),EVP 统一了各种加密算法的调用方式:

1
2
3
4
5
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
EVP_DigestInit_ex(ctx, EVP_md5(), NULL); // 或 EVP_sm3()、EVP_sha256()
EVP_DigestUpdate(ctx, data, len);
EVP_DigestFinal_ex(ctx, out, &out_len);
EVP_MD_CTX_free(ctx);

哈希列表(Hash List) 验证文件完整性:将文件分块分别计算哈希,再把所有块的哈希值拼接后计算总哈希,常用于大文件校验。

Merkle Tree 更进一步,将哈希值两两配对逐层向上计算,最终得到一个根哈希。这种结构可以在不下载完整文件的情况下验证某个数据块是否被篡改,广泛用于区块链和 P2P 网络。

DES 加解密

OpenSSL 提供了 DES_set_key、DES_ecb_encrypt、DES_cbc_encrypt 等接口。ECB 模式存在严重的安全缺陷——相同明文块产生相同密文块,攻击者可识别数据模式,因此实际工程应使用 CBC 或更安全的模式。

时间线

时间 事件
6月 项目申请
7月11日 与 k1 老师首次交流,确定项目方向
7月19日 与肖老师通话确认进展
7月22-25日 OpenSSL 学习:环境搭建、Base64、BIO、哈希、DES
7月22日 到家,开始学习 OpenSSL

开源之夏01:项目启动与OpenSSL入门
https://47.108.189.123/2025/07/25/开源之夏/01-项目启动与OpenSSL入门/
Author
Dong
Posted on
July 25, 2025
Licensed under