You need to enable JavaScript to run this app. OpenSSL EVP API加解密异常:长串解密报错、关填充致空输出/段错误
优惠活动
大模型
产品
解决方案
定价
更多

OpenSSL EVP API加解密异常:长串解密报错、关填充致空输出/段错误

异常根因定位

所有报错本质上是do_crypt函数对OpenSSL EVP接口的参数约定、返回值处理存在系统性偏差,具体拆解如下:

为什么长字符串加密后解密会触发bad decrypt错误

  • 短字符串能正常加解密完全是巧合:长度11的"Hello world"小于AES-128的16字节块长,块模式下EVP_CipherUpdate需要攒够完整块才会输出密文,因此这一步不会产生任何输出,回传的长度值为0。后续调用EVP_CipherFinal_ex时,哪怕代码没有做缓冲区位置偏移,也会因为初始输出位置在缓冲区起始处,刚好把带填充的完整块密文写到正确位置,流程能跑通。
  • 长字符串就会暴露核心代码bug:以长度24的"Hello world! How are you?"为例,输入长度超过16字节块长,EVP_CipherUpdate会先处理第一个完整块,输出16字节密文到缓冲区,同时通过outlen参数回传这16字节的长度。
  • 两个致命错误直接破坏密文完整性:
    • 原代码调用EVP_CipherFinal_ex时,传入的输出指针仍然是缓冲区的起始地址outbuf.data(),没有偏移到Update已经写完的位置(即outbuf.data() + outlen),导致Final阶段生成的带PKCS#7填充的最后一块密文,直接覆盖了Update阶段已经写好的第一块密文。
    • EVP_CipherFinal_ex回传的outlen值是Final阶段自身生成的密文长度,完全覆盖了Update阶段的输出长度,最终加密返回的总密文长度、内容都完全错乱。
  • 用这串损坏的密文解密时,最后一块的填充值根本不符合PKCS#7的格式校验规则,自然会在Final阶段报bad decrypt错误。

为什么关闭填充后会出现空输出、甚至段错误

  • 空输出的本质是outlen值被Final接口直接覆盖:
    • 测试用的"Some Crypto Text"刚好为16字节,关闭填充后不需要做块补位,EVP_CipherUpdate会直接输出完整的16字节密文,回传outlen=16。
    • 后续调用EVP_CipherFinal_ex时,因为没有填充需要处理,Final阶段不会输出任何字节,会直接把传入的outlen变量值覆盖为0。
    • 函数返回时调用方拿到的outlen为0,构造字符串时从缓冲区起始位置取0长度的内容,自然输出为空。
  • 段错误的本质是错误分支的越界访问:
    • 在原16字节测试字符串基础上新增1个字符后,总长度为17字节,不是AES块长的整数倍,关闭填充模式时EVP接口会直接返回错误,打印"data not multiple of block length"的原因提示。
    • 原代码在错误分支直接返回空的std::vector<unsigned char>,但作为引用参数传入的outlen值还停留在之前Update阶段写入的16字节。
    • 调用方拿到空vector后,直接尝试访问out.begin() + outlen,也就是对长度为0的vector做16字节的偏移访问,完全越界,直接触发段错误。
  • 额外的叠加影响:原代码将加密后的二进制密文直接转为std::string跨函数传递,虽然std::string本身支持存储二进制空字符,但密文中的不可打印字节在控制台输出时本来就无法正常显示,和代码bug叠加后进一步放大了异常的表现。

内容的提问来源于stack exchange,提问作者TomateVerde

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.02 22:54:01