You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EVP加密是顺序式还是有状态?AES-GCM模式TCP传输加密异常咨询

问题描述

我尝试用OpenSSL的EVP加密库对TCP套接字传输的消息做加解密。流程是先通过EVP_CIPHER_CTX_new()创建密码上下文,再调用EVP_EncryptInit_ex(enctx, EVP_aes_256_gcm(), NULL, crypkey, iv)完成初始化,之后用EVP_EncryptUpdate加密数据再通过套接字发送。

如果每次调用EVP_EncryptUpdate后立刻调用socket的send发送,一切正常;但如果先把加密后的数据存起来,之后再发送,加密数据就会损坏。

我是新手,想知道这是设计特性,还是我漏了关键细节?

后来查资料发现GCM模式在加解密两端都会维护计数器,是不是说明EVP_EncryptUpdate是基于状态的操作?

比如下面的示例代码,当我只发送enpkt2时,服务器接收端会拒绝,因为它期望先收到第一个加密包,否则客户端和服务器的上下文会不同步。这个理解对吗?

EVP_CIPHER_CTX *enctx;

enctx = EVP_CIPHER_CTX_new();    

if (1 != EVP_EncryptInit_ex(enctx, EVP_aes_256_gcm(), NULL, crypkey, iv))
    printf("ENCRYPT init failed\n");    

unsigned char *pkt1, *enpkt1, *pkt2, *enpkt2;   

int ciplen1, ciplen2;

if (1 != EVP_EncryptUpdate(enctx, enpkt1, &ciplen1, pkt1, pktlen1))
    printf("encrypt error\n");

if (1 != EVP_EncryptUpdate(enctx, enpkt2, &ciplen2, pkt2, pktlen2))
    printf("encrypt error\n");

send(socket, enpkt2, ciplen2);
解答

你的理解完全正确,核心问题在于GCM模式的上下文是带状态的,EVP_EncryptUpdate会持续修改这个状态。

  • GCM属于流密码模式,依赖递增的计数器(作为IV的一部分)生成加密流密钥。每次调用EVP_EncryptUpdate时,上下文内的计数器会根据加密数据长度自动递增,后续加密操作都基于更新后的计数器状态执行。
  • 你先加密pkt1再加密pkt2,enpkt2是基于pkt1加密后的计数器状态生成的密文。但服务器端的解密上下文从初始IV开始,会先等待对应pkt1的密文来同步计数器状态,直接收到enpkt2时计数器完全不匹配,解密必然失败。

为什么"加密后立即发送"能正常工作?

因为此时你按顺序发送enpkt1、enpkt2,服务器端也按顺序解密,每一次解密都会同步更新自身的计数器状态,和客户端的上下文保持一致,因此可以正常解密。

解决"先存储后发送"问题的方案

  • 如果要分批存储密文再统一发送,必须按加密顺序存储所有密文,最终按顺序发送,不能跳过前面的部分。
  • 若需要独立加密多个数据包(每个包可单独发送、解密),则每个数据包都要创建独立的EVP上下文,并且使用唯一的IV/计数器起始值(GCM要求每个加密会话或数据包的IV不能重复)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 23:35:30