如何在OpenSSL中获取AES-CCM解密生成的TAG并返回给客户端
解决AES-CCM解密时返回生成TAG给客户端的问题
看起来你已经把OpenSSL AES-CCM的机制摸得很透彻了——默认流程是预先传入预期TAG,由OpenSSL内部验证并仅在匹配时输出有效明文,但你的需求是要把解密过程中生成的TAG返回给客户端,让客户端自行完成比对。其实只需要调整一下对OpenSSL上下文的控制命令就能实现,我给你梳理具体步骤和代码示例:
核心思路
OpenSSL的EVP接口提供了EVP_CTRL_CCM_GET_TAG命令,用来提取解密过程中计算出来的TAG值,而非像你之前用的EVP_CTRL_CCM_SET_TAG那样传入预期值做验证。这样即使TAG不匹配,你也能拿到生成的TAG,再返回给客户端做比对。
具体实现步骤
- 初始化解密上下文:和常规流程一致,创建并初始化
EVP_CIPHER_CTX,设置AES-CCM算法、密钥、IV,同时别忘了设置附加数据(AD,如果你的应用用到的话)和明文/密文的长度。 - 执行解密操作:调用
EVP_DecryptUpdate和EVP_DecryptFinal_ex处理密文,得到明文。这里要注意:即使后续TAG验证失败,EVP_DecryptFinal_ex会返回错误,但我们仍然可以获取生成的TAG,所以不要直接在这个错误点终止流程。 - 提取生成的TAG:调用
EVP_CIPHER_CTX_ctrl,使用EVP_CTRL_CCM_GET_TAG命令,指定TAG长度,把生成的TAG读取到缓冲区中。 - 返回TAG给客户端:将提取到的TAG和明文一起返回给客户端,由客户端用本地存储的TAG进行比对。
代码示例
// 假设已完成上下文初始化:ctx已创建,密钥、IV、AD等已设置 unsigned char plaintext[1024]; int decrypted_len = 0; int final_len = 0; // 解密密文 if (!EVP_DecryptUpdate(ctx, plaintext, &decrypted_len, ciphertext, ciphertext_len)) { handleErrors(); } // 完成解密(即使TAG不匹配,这里返回错误,但我们仍能获取TAG) if (!EVP_DecryptFinal_ex(ctx, plaintext + decrypted_len, &final_len)) { // 可以在这里记录TAG不匹配的日志,但不要终止流程 } decrypted_len += final_len; // 提取解密生成的TAG(这里假设TAG长度是14字节,和加密时一致) unsigned char generated_tag[14]; if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, 14, generated_tag)) { handleErrors(); } // 现在将plaintext和generated_tag返回给客户端,由客户端比对存储的TAG
关键注意事项
- TAG长度一致性:确保解密时指定的TAG长度和加密时完全相同(CCM支持4/6/8/10/12/14/16字节),否则提取的TAG会不正确。
- 安全比对:客户端在比对两个TAG时,一定要使用恒定时间比较算法,避免时序攻击泄露TAG信息。
- 上下文生命周期:要在
EVP_CIPHER_CTX销毁前完成TAG提取,一旦上下文被释放,TAG数据就无法获取了。
结合你提到的e_aes.c第3835行的实现,OpenSSL确实是在解密过程中逐步计算TAG值,EVP_CTRL_CCM_GET_TAG就是把这个计算后的结果拷贝出来,完全符合你的需求。
内容的提问来源于stack exchange,提问作者suman reddy
相关产品推荐
相关产品推荐

