资讯动态

OpenSSL 1.0.2u源码编译、TLS握手与二次开发实践

发布时间:2026/10/26 14:08:27 来源:尧图企业网站定制
简介openssl-1.0.2u.tar 是 OpenSSL 1.0.2u 版本的源代码归档包面向从事网络编程、系统安全与运维工作的开发者及学习者用于集成 SSL/TLS 加密通信、证书管理与密码学算法支持也可作为理解编译安装流程的实践材料。压缩包整体约 5.11MB文件总数标注为 0文件类型明细暂未提供形态为 gz 源码包适合源码获取与本地留存核心在于可配置、编译并安装出库文件与命令行工具。已有 412 人学习或下载说明其在特定版本源码获取与安全通信学习中具有一定参考需求。读者可据此了解 OpenSSL 库如何提供多种对称与非对称加密算法、证书操作、哈希函数和安全协议实现同时可结合配置、编译、安装过程梳理常见安全通信场景中的连接思路并关注该版本包含的安全修复与性能优化为后续排查兼容性与安全问题提供依据。1. 一台老网关的加密库崩溃后我最后靠这份 1.0.2u 源码包重新编译接手一套跑在内网的老网关时最容易出问题的往往是被硬链接到旧版加密库上的那部分业务代码问题反而不是最先暴露的。系统升级之后libssl的 soname 一变整条 TLS 链路就直接起不来报错还停在undefined symbol这种级别排查过程相当麻烦。这次能救场的就是这份openssl-1.0.2u.tar——1.0.2 分支收尾阶段的完整 C 源码包协议栈、算法实现、命令行工具、回归测试全在里面解包之后不联网、不拉任何第三方依赖直接./config make就能产出libcrypto、libssl和openssl可执行文件。它适合三类人要给旧系统补一个版本可控的加密库的运维要给嵌入式板子交叉编译一套 TLS 栈的驱动开发以及想读一份工业级 C 代码练手的后端。它确实不新但胜在完整可复现从Configure到make test的每一步都在包内是少数能让人从零编译一路走到握手成功的完整工程样本。2. 版本与骨架1.0.2u 里必须先搞清的目录和构建脚本拿到一个 tar 包很多人第一反应是直接tar -xzf然后./configure结果发现根本没有configure只有一个config和一个Configure。这一步就会卡住不少人。先把版本号和目录分工摸清楚后面所有操作都会顺很多。2.1 版本号拆开看1.0.2 与末尾那个字母位 u1.0.2是主版本线末尾的字母是补丁位每修一批问题字母往后挪一位。字母位走到u的时候这支分支基本也到头了所以拿到1.0.2u差不多等于拿到 1.0.2 全系最后的样子——这是个很实用的判断你需要兼容的老系统大概率就是照着这个 ABI 编的。和更早的 1.0.1 相比1.0.2 这条线把 ALPN 扩展补了进来顺手把一些算法套件的默认行为收紧了一轮。放到今天看这些都不算亮点但如果你要对接的是一个只认 1.0.2 的对端这些差异点就是你排查握手失败的入口。真正要留意的是 ABI 层面的两处硬差异它们直接决定你能不能把这个包装上对比项1.0.2 系列1.1.x 及以后动态库 sonamelibssl.so.1.0.0/libcrypto.so.1.0.0libssl.so.1.1起跳EVP_CIPHER_CTX结构体可栈上直接声明不透明指针必须_new()/_free()初始化/清理EVP_CIPHER_CTX_init/_cleanup统一到_new/_free头文件包含openssl/xxx.h平铺部分宏与结构体改为访问器函数第二行是移植阶段踩得最多的一处问题。网上大量 1.0.2 时代的示例代码都写成EVP_CIPHER_CTX ctx;然后EVP_CIPHER_CTX_init(ctx);这段代码在 1.1.x 上编译直接不通过反过来把 1.1.x 的写法搬进 1.0.2 也一样。所以看示例代码之前先确认它属于哪个时代。2.2 目录分工crypto、ssl、apps 三层各管一段解包之后第一眼看目录会觉得杂乱实际分工很清晰按「算法 → 协议 → 工具」三层切目录里面放什么什么时候会翻它crypto/算法与底层原语bn大数、rsa、ec、evp、bio、asn1、x509、rand要改算法实现、加自定义摘要、追随机数问题ssl/协议状态机握手、记录层、会话缓存、s2/s3/t1各方法实现要调 TLS 版本、密码套件、会话复用策略apps/命令行工具openssl.c是总入口每个子命令一个.c要加自己的子命令或者想抄enc、s_client的写法engines/硬件加速引擎接口与几个内置引擎要接密码卡、要走国密硬件include/openssl/对外头文件安装后整个拷到$prefix/include写业务代码时 include 的就是这里test/回归测试与测试向量make test跑到哪一步挂了来这里看用例util/一堆 perl 脚本证书生成、构建辅助、错误码生成加错误码、改构建流程demos/各语言的调用示例C 和 Perl 为主不确定某个 API 怎么用时先翻这里有个经验crypto/evp/是整份代码的抽象中枢crypto/bio/是 I/O 中枢ssl/里的记录层读写最终都会落到 BIO 上。把这两个目录读明白ssl/那部分基本就不需要逐行看了。2.3 从 Configure 到 Makefile构建脚本怎么读懂这里没有configure只有Configureperl 写的和config一层 shell 包装。整个构建流程是Configure接收一个「目标名」和一堆no-xxx/enable-xxx开关去替换Makefile.org模板里的变量最终吐出Makefile。目标名不是随便写的是Configure内部一张表里列出来的几百个交叉编译用的工具链前缀也在里面。不确定的时候先让它列一遍cd openssl-1.0.2u # LIST 会把所有可选目标打印出来grep 一下自己的平台 perl Configure LIST | grep -i linux # 生成 Makefile # --prefix 安装根目录二进制和库装这里 # --openssldir 配置和证书目录openssl.cnf 会放这里和 prefix 分开是有意的 # shared 产出动态库.so不加就是纯静态 # no-asm 关掉汇编优化交叉编译或老工具链报错时的保命开关 ./config --prefix/opt/app-crypto --openssldir/opt/app-crypto/ssl shared no-asm三个参数里最容易搞错的是--prefix和--openssldir的关系。前者装程序后者装openssl.cnf和证书目录。如果只给--prefix不给--openssldir配置文件的默认路径会回落到编译期的内置值装完之后openssl一跑就提示找不到配置这是个非常经典的坑后面避坑章节还会再提。no-asm这个开关值得单独说它关掉的是手写汇编实现的大数运算和 AES 加速。关掉之后性能会掉具体掉多少看你用什么算法AES 和 RSA 签名受影响最明显但换来的是不依赖具体汇编器和 GNU as 版本交叉编译时成功率会高出一大截。开发调试阶段先关掉等跑通了再打开做一次性能对比是我通常的做法。配置生成了之后Makefile里的depend规则还可以重算一次头文件依赖。老版本里这一步有时候是必要的尤其是你打算改include/openssl/下头文件的时候# 重算依赖可选改过头文件之后建议跑一次 make depend # 并行编译nproc 拿不准就直接看 CPU 核数 make -j$(nproc)make depend会扫一遍所有源文件的 include 关系重写Makefile里的依赖段耗时不算短但改过头文件不重算的话make可能只重编一部分文件最后链接出奇怪的符号错误。这种错误排查起来非常费时建议在改动头文件之后执行。3. 编译跑通从解包到本地 TLS 握手自测的完整命令链路这一章把完整链路走一遍从环境准备到最后自己跟自己握手成功。中间每一步都给命令和判断标准照这个顺序走一遍能省掉大量反复猜测的时间。3.1 环境准备与解包依赖其实很少一个 C 编译器、make、perl 5。zlib 是可选的只有你要开zlib压缩支持才需要zlib-devel。perl 是硬依赖因为Configure本身和util/下的一堆脚本都是 perl 写的缺了它连 Makefile 都生成不出来。# 先确认三件套在不在版本不用太新 gcc --version | head -1 make --version | head -1 perl -v | grep -i version # 解包注意包名目录结构是 openssl-1.0.2u/没有多余的嵌套层 tar -xzf openssl-1.0.2u.tar cd openssl-1.0.2u # 看一眼包里的说明INSTALL 和 README 不长但信息密度高 ls INSTALL README CHANGES NEWSCHANGES这个文件不要跳过。里面按版本倒序列了每一处行为变更你在 1.0.2u 上遇到的「怎么跟文档写的不一样」八成能在里面找到对应条目。3.2 三种编译方式与参数怎么选同样是这份源码编译方式不同最后得到的产物差别很大选错了会在部署阶段给你带来麻烦。# 姿势一纯静态最省事。产物是 libcrypto.a / libssl.a # 好处是业务程序编出来不依赖外部 .so扔到任何机器上都能跑 # 坏处是体积大而且必须重新链接才能升级 ./config --prefix/opt/app-crypto --openssldir/opt/app-crypto/ssl no-shared make -j$(nproc) make install # 姿势二动态库。加 shared编译时自动带 -fPIC # 装完必须处理运行库搜索路径否则业务程序跑起来还是找到系统那份 ./config --prefix/opt/app-crypto --openssldir/opt/app-crypto/ssl shared make -j$(nproc) make install # 姿势三交叉编译把工具链前缀塞进去同时关汇编 # 这里以 arm 为例实际按你板子的三元组改 ./config --prefix/opt/arm-crypto --openssldir/opt/arm-crypto/ssl \ --cross-compile-prefixarm-linux-gnueabihf- \ shared no-asm no-tests make -j$(nproc) make install姿势三里的no-tests是交叉编译时的实用开关测试用例编出来在本机跑不了纯属浪费时间。要验证的话等固件烧到板子上之后再跑openssl speed和s_client。make test要不要跑我建议至少完整跑一次看它有没有在你这个平台上出问题# 全量回归会跑几万个用例慢的话十几分钟 make test # 只想验证几个关键算法用 apps 里的子命令更快 apps/openssl speed aes-256-cbc rsa2048make test偶尔会有一两个用例失败但装完一切正常——这类失败多数和测试环境的时间、文件权限、随机数熵池有关不一定是算法实现的问题。判断方法是看失败用例名涉及test_rand、test_ca这类外围逻辑的可以先放涉及test_enc、test_evp、test_ssl的就必须查到底。3.3 安装后的目录布局与运行库路径make install之后--prefix下面会长出这么几块路径内容bin/openssl命令行主程序所有子命令都是它的入口lib/libcrypto.so.1.0.0算法库动态方式才有lib/libssl.so.1.0.0协议库lib/pkgconfig/openssl.pc给 pkg-config 用include/openssl/头文件全量拷贝ssl/openssl.cnf默认配置由--openssldir决定位置ssl/certs、ssl/private证书与私钥目录make install会建好动态方式装完之后不处理搜索路径的话你的程序跑起来会静默加载系统自带的旧库。这个问题很隐蔽编译期用的是新头文件链接期可能连的是系统libssl.so运行期又加载了另一个版本最后表现为「明明编进去了却找不到符号」。# 让动态链接器优先找我们自己的目录 echo /opt/app-crypto/lib /etc/ld.so.conf.d/app-crypto.conf ldconfig # 确认注册成功看输出里有没有我们装的这一份 ldconfig -p | grep -E libssl|libcrypto # 看某个具体程序到底链了谁这是排查库冲突的第一手证据 ldd /opt/app-crypto/bin/openssl | grep -E ssl|cryptoldd那一步是关键。如果它指向系统目录而不是/opt/app-crypto/lib说明ldconfig没生效或者LD_LIBRARY_PATH的优先级被其他配置压过了。临时验证可以直接export LD_LIBRARY_PATH/opt/app-crypto/lib但生产环境还是走ld.so.conf.d不然换个登录方式就失效。3.4 自测版本、握手、证书链一次验证完装完先确认跑的是哪一份/opt/app-crypto/bin/openssl version -a # OPENSSLDIR 那一行必须指向你 --openssldir 指定的路径 # built on 和 platform 能帮你确认是不是编对了架构然后不依赖任何外部服务自己造证书、自己起服务端、自己连自己把 TLS 握手链路完整走一遍# 1. 造一张 30 天有效期的自签证书CN 随便写本地测不看域名 /opt/app-crypto/bin/openssl req -x509 -newkey rsa:2048 -nodes \ -keyout /tmp/k.pem -out /tmp/c.pem -days 30 -subj /CNtest.local # 2. 起一个本地 TLS 服务端-www 让它回一段 HTTP 页面方便看 /opt/app-crypto/bin/openssl s_server -accept 4433 \ -cert /tmp/c.pem -key /tmp/k.pem -www # 3. 客户端连一下只允许 TLS1.2 且限定套件避免默认值掩盖问题 /opt/app-crypto/bin/openssl s_client -connect 127.0.0.1:4433 \ -CAfile /tmp/c.pem -verify_return_error -tls1_2s_client的输出里重点看三行Protocol是不是你限定的版本Cipher是不是你期望的套件最后一行Verify return code是不是0 (ok)。三行都对说明算法库、协议栈、证书链校验、随机数这几条路都是通的。提示-verify_return_error这个参数一定要加。不加的话证书校验失败时s_client只打印一行警告就继续握手很容易让人误以为链路正常。4. 核心代码拆解EVP 抽象层、BIO 流与 apps 的调用链跑通只是第一步要真正改得动代码得搞清楚这三个东西的关系。一句话概括apps/是使用方ssl/是协议层底下干活的是crypto/而crypto/里把杂乱的算法统一成一致接口的那一层就是 EVP把文件、内存、socket 统一成流的那一层就是 BIO。4.1 EVP 接口用一套调用形式调用所有算法EVP 的思路是把「算法」抽象成一个带函数指针表的结构体然后所有算法用同一组Init / Update / Final调用。业务代码只认EVP_CIPHER和EVP_MD具体是 AES 还是 SM4在运行时决定。下面这段是 1.0.2 风格的 AES-256-GCM 加密注意ctx是栈上对象#include openssl/evp.h #include string.h /* * AES-256-GCM 加密。 * key: 32 字节iv: 12 字节tag 输出 16 字节 * aad/aadlen 是附加认证数据没有就传 NULL/0。 * 返回密文长度失败返回 -1。 */ int aes_gcm_seal(const unsigned char *key, const unsigned char *iv, const unsigned char *aad, int aadlen, const unsigned char *in, int inlen, unsigned char *out, unsigned char *tag) { EVP_CIPHER_CTX ctx; /* 1.0.2 允许栈上声明1.1.x 之后这行编译不过 */ int len 0, total 0; EVP_CIPHER_CTX_init(ctx); /* 第一步选算法。后三个参数先传 NULL密钥和 IV 留到下一次 Init */ if (EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL) ! 1) goto err; /* 第二步GCM 的 IV 长度要单独设默认 12 字节改长度必须走这个 ctrl */ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL) ! 1) goto err; /* 第三步真正喂 key 和 iv。算法参数传 NULL 表示沿用上一步选的 */ if (EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv) ! 1) goto err; /* 第四步AAD 必须在明文之前喂输出缓冲传 NULL */ if (aad aadlen 0) { if (EVP_EncryptUpdate(ctx, NULL, len, aad, aadlen) ! 1) goto err; } /* 第五步加密。输出长度最多比输入多一个分组长所以缓冲要留 16 字节余量 */ if (EVP_EncryptUpdate(ctx, out, len, in, inlen) ! 1) goto err; total len; /* 第六步GCM 下 Final 不产密文但必须调用否则 tag 算不出来 */ if (EVP_EncryptFinal_ex(ctx, out total, len) ! 1) goto err; total len; /* 第七步取认证标签16 字节是 GCM 的标准长度 */ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag) ! 1) goto err; EVP_CIPHER_CTX_cleanup(ctx); return total; err: EVP_CIPHER_CTX_cleanup(ctx); /* 出错也要清不然内部引擎资源泄漏 */ return -1; }几个参数和调用顺序上的注意点都是实际写错过才知道的EVP_EncryptInit_ex被调用了两次第一次只传算法第二次算法传NULL。这是 EVP 的固定套路——算法相关的一次性配置比如 GCM 的 IV 长度必须在两次 Init 之间做顺序反了SET_IVLEN会返回 0。EVP_EncryptUpdate在喂 AAD 时输出参数传NULL但长度指针不能传NULL这是个细节传了就直接崩。EVP_EncryptFinal_ex在 GCM 模式下看着像个空调用但拿掉它GET_TAG必然失败。这种「必须调但看起来没用」的接口在 EVP 里有好几处习惯就好。输出缓冲要留余量。分组密码的Update会按块处理理论上最多多出一个分组也就是 16 字节。用inlen 16开缓冲最稳。如果换成摘要套路几乎一样只是把EVP_Encrypt*换成EVP_Digest*把EVP_CIPHER_CTX换成EVP_MD_CTX。这也是 EVP 这层抽象的价值学会一个剩下的照着换名字就行。4.2 BIO 流文件、内存、socket 都是同一种东西BIO 是另一套抽象。它把「读写的两端」统一成BIO对象然后支持把多个 BIO 串成链数据从链头流进去一层层加工到链尾。常见的加工层有 base64 编解码、缓冲区、摘要计算常见的数据源有文件、内存块、socket 连接。#include openssl/bio.h #include openssl/evp.h /* 把一段数据以 base64 写入文件验证 BIO 链的组装方式 */ int write_base64_file(const char *path, const unsigned char *data, int len) { BIO *file BIO_new_file(path, w); BIO *b64 BIO_new(BIO_f_base64()); BIO *chain; if (!file || !b64) { BIO_free(file); BIO_free(b64); return -1; } /* 默认每 64 字符折一行关掉之后整段输出便于下游解析 */ BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); /* push 把 b64 插到 file 前面返回新的链头 */ chain BIO_push(b64, file); while (len 0) { int n BIO_write(chain, data, len); if (n 0) { BIO_free_all(chain); return -1; } data n; len - n; } BIO_flush(chain); /* 不 flush 尾部数据留在缓冲区里文件会少一截 */ /* 只释放链头整条链会跟着释放。千万别再单独 BIO_free(file) */ BIO_free_all(chain); return 0; }BIO_push的返回值容易被忽略——它返回的是新的链头不是原来那个。如果写成BIO_push(b64, file);然后继续用b64写数据有时候能跑有时候不行取决于 b64 是不是已经是链头。这是典型的玄学 bug写成chain BIO_push(...)然后全用chain能省掉一整天的排查。BIO_free_all和BIO_free的区别也得记牢BIO_free_all从链头开始把整条链拆掉BIO_free只拆一个。链式结构上混用必然导致双重释放或者泄漏。在ssl/里这套东西是核心。握手阶段的每条记录最终都通过BIO_read/BIO_write进出s_client之所以能连远端是因为它用BIO_new_ssl_connect造了一条「内存缓冲 SSL 过滤 socket 连接」的三层链。你如果要做的是在已有 socket 上接管 TLS正确姿势就是造一个BIO_new_socket塞进SSL_set_bio而不是自己去读写 fd。4.3 apps 目录命令行工具的组合方式openssl这个命令能认出enc、req、s_client等几十个子命令靠的是一张静态表加一次线性查找。apps/openssl.c里维护了一张函数表main拿到argv[1]之后在表里找名字找到就调对应的xxx_main。表的结构简化掉宏之后大致是这样/* apps/apps.h 附近省略了按特性开关裁剪的宏分支 */ typedef struct { const char *name; /* 子命令名如 enc */ int (*func)(int argc, char **argv); /* 实际入口如 enc_main */ } FUNCTION; /* apps/openssl.c 里的静态表加子命令就往这里加一行 */ static FUNCTION functions[] { { enc, enc_main }, { req, req_main }, { s_client, s_client_main }, { NULL, NULL } /* 结尾哨兵查找循环靠它停 */ };这个设计带来一个很好的效果每个子命令都是独立的xxx_main参数解析各自用util/里的通用选项解析器处理互不干扰。想给openssl加自己的命令成本就是新建一个.c、写一个xxx_main、在表里加一行、在Makefile里加一个目标没有更复杂的东西。apps/enc.c值得当范文读。它把 EVP 的对称加解密完整包了一遍支持各种填充模式、KDF 派生、base64 包装代码量不大但把EVP_CIPHER_CTX的生命周期管理写得非常干净。自己写业务封装之前先看它一遍能少走不少弯路。5. 避坑清单编译、链接、证书路径上最容易翻车的五处下面这五条都是实际遇到过的按「现象 → 原因 → 解决」写照着对号入座就行。5.1 编译期汇编器和可选依赖第一条交叉编译到一半报汇编语法错误。现象make跑到crypto/bn/asm/或者crypto/aes/asm/下面的文件时挂掉报Error: selected processor does not support ...或者unrecognized instruction。原因这套代码里的汇编是给特定平台写的交叉编译工具链的汇编器版本或者目标架构特征跟它不匹配。老工具链尤其容易出。解决加no-asm重新./config。功能完全不受影响只是大数运算和对称加密会慢一些。先关掉把流程跑通等有性能要求了再单独针对某个算法打开汇编验证。第二条zlib.h: No such file or directory。现象配置阶段没报错make到一半提示找不到zlib.h。原因zlib支持默认是开的但系统里只有运行库没有开发头文件。解决两条路——装zlib-devel或者对应的开发包或者直接no-zlib关掉。压缩支持在 TLS 里本来就是可选项关掉不影响握手。5.2 链接期-fPIC、soname 与系统库冲突第三条relocation R_X86_64_32 against ... can not be used when making a shared object; recompile with -fPIC。现象不是编这个库的时候报的而是你拿它编出来的.a去链接自己的.so时报的。原因默认是no-shared编译产物是静态库编译时没带-fPIC里面的代码不是位置无关的没法塞进动态库。解决要么改成shared重新编自动带-fPIC要么保持静态但业务侧也静态链接。混着用来最麻烦这个报错就是混用的典型症状。第四条装完了程序跑起来用的还是系统那份旧库。现象编译期全新头文件ldd一看链的却是/usr/lib64/libssl.so.1.0.0。表现是某些新接口调用返回异常或者行为跟预期完全不符。原因动态链接器的搜索顺序里系统路径优先级高于--prefix装的目录。LD_LIBRARY_PATH在部分场景下也不生效比如 setuid 程序。解决写ld.so.conf.d然后ldconfig用ldd和ldconfig -p双重确认。静态编译能彻底绕开这个问题代价是每次升级都要重新链接所有使用方。5.3 运行期配置文件和证书目录第五条Unable to load config info from /usr/local/ssl/openssl.cnf。现象openssl能跑但任何涉及配置的子命令req、ca、x509都提示找不到配置文件。原因--openssldir没给配置路径回落到编译期内置的默认值而那个目录在你机器上不存在。解决重新./config时显式给--openssldir或者临时用OPENSSL_CONF环境变量指过去。前面提过这个坑它值得出现两次因为中招率实在太高。注意--prefix和--openssldir建议分开设把配置和证书放独立目录。混在一起的话将来卸库重装容易把证书一起删掉。6. 二次开发在这份旧分支上加子命令和业务封装层的做法在这份包上做二次开发最省力的两个落点是「加一个 openssl 子命令」和「加一层业务封装」。前者用来做内部工具后者用来把 EVP 的生命周期管起来。加子命令的成本很低。新建apps/mycmd.c写一个int mycmd_main(int argc, char **argv)参数解析抄apps/enc.c的开头几行然后在apps/openssl.c那张functions[]表里加一行注意加在结尾哨兵之前最后在Makefile里把mycmd.o加进APPS对应的目标列表。改完make一次./apps/openssl mycmd就能用。封装层的价值在错误处理上。EVP 的每个调用都可能失败但错误信息默认躺在ERR队列里需要主动ERR_get_error取。我一般会包一层/* my_crypto.h把 ctx 生命周期和错误码收口业务侧只看到 0 / -1 */ int my_aes_gcm_encrypt(const unsigned char *key, const unsigned char *iv, const unsigned char *in, int inlen, unsigned char *out, unsigned char *tag);实现里做三件事进入时ERR_clear_error()清空队列中途每个失败点用goto err收拢出口统一EVP_CIPHER_CTX_cleanup并把ERR_get_error()的返回值返回给调用方记日志。这样业务代码里就不会出现到处ERR_print_errors_fp(stderr)的情况。改造之后怎么验证三步走改造点落点文件验证方式新增子命令apps/mycmd.c、apps/openssl.c、Makefileopenssl mycmd -h能出帮助openssl list-standard-commands能看到名字算法封装my_crypto.c用 NIST 的标准测试向量跑加解密密文和 tag 逐字节比对行为改动crypto/或ssl/下make test全量跑一次再补一个自己的回归脚本向量比对这一步不能省。自己写加密代码最容易出的错不是算法写错而是参数顺序、IV 长度、AAD 时机这些细节错而这几个错在密文长度上完全看不出来只有逐字节比对才能发现。踩过的坑有一次改完一个摘要封装测了加解密都正常单元测试全绿上了联调环境才发现在某个特定输入长度下计算结果会差一个字节。原因是我自己写的缓冲长度计算用了int但输入长度传进来时没做边界检查。从那以后我每次改这类封装都强制走一遍「标准向量 边界长度 空输入 超长输入」这四个用例不管改动多小。加密这东西没有中间状态要么全对要么全错想靠肉眼 review 发现问题基本指望不上。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑