用户态下用内核Crypto API实现AES-GCM遇参数无效错误求助
问题分析与修复方案
你遇到的「Invalid Argument」错误来自以下几处代码逻辑问题,逐一修正即可解决:
1. ALG_SET_AEAD_AUTHSIZE 参数传递错误
setsockopt 的 ALG_SET_AEAD_AUTHSIZE 选项需要传入标签长度的指针,而非直接将长度作为 optlen 参数。原代码传入 NULL 作为 optval,导致内核无法获取正确的标签长度:
原错误代码:
int setTag = setsockopt(tfmfd, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL, taglen);
修正后:
int setTag = setsockopt(tfmfd, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, &taglen, sizeof(taglen));
2. 控制消息长度计算错误
ALG_SET_OP 的 cmsg_len 错误
CMSG_LEN() 用于计算控制消息的总长度(包含 cmsghdr 结构和数据部分),不需要嵌套 CMSG_SPACE()。原代码多套一层导致长度计算过大:
原错误代码:
cmsg->cmsg_len = CMSG_LEN(CMSG_SPACE(sizeof(uint32_t)));
修正后:
cmsg->cmsg_len = CMSG_LEN(sizeof(uint32_t));
ALG_SET_IV 的 cmsg_len 错误
struct af_alg_iv 的实际大小是 ivlen(4字节)加上IV数据长度(12字节),原代码直接用 sizeof(initVector) 计算,未考虑结构本身的 ivlen 字段:
原错误代码:
cmsg->cmsg_len = CMSG_LEN(CMSG_SPACE(sizeof(initVector)));
修正后:
iv = (void *)CMSG_DATA(cmsg); iv->ivlen = 12; memcpy(iv->iv, initVector, 12); // 基于实际IV结构大小计算cmsg_len cmsg->cmsg_len = CMSG_LEN(sizeof(struct af_alg_iv) - sizeof(iv->iv) + iv->ivlen);
3. 缺少AAD数据发送逻辑
设置 ALG_SET_AEAD_ASSOCLEN 后,必须通过 sendmsg 发送对应长度的AAD数据,但原代码的 msg_iov 为空,内核无法获取AAD数据,导致参数不匹配。需要添加AAD的iovec配置:
在准备消息时补充:
// 对应aadSize=8的示例AAD数据 char aad_data[] = "testaad12"; struct iovec iov = { .iov_base = aad_data, .iov_len = aadSize }; msg.msg_iov = &iov; msg.msg_iovlen = 1;
完整修正后的核心代码片段
// 修正ALG_SET_AEAD_AUTHSIZE调用 int setTag = setsockopt(tfmfd, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, &taglen, sizeof(taglen)); assert(setTag >= 0); // ... 省略其他代码 ... // Prepare Message struct msghdr msg = { 0 }; struct cmsghdr *cmsg = NULL; char cbuf[128] = {0}; char aad_data[] = "testaad12"; // 对应aadSize=8的AAD数据 struct iovec iov = { .iov_base = aad_data, .iov_len = aadSize }; msg.msg_control = cbuf; msg.msg_controllen = sizeof(cbuf); msg.msg_iov = &iov; msg.msg_iovlen = 1; // 设置加密操作类型 cmsg = CMSG_FIRSTHDR(&msg); assert(cmsg != NULL); cmsg->cmsg_level = SOL_ALG; cmsg->cmsg_type = ALG_SET_OP; cmsg->cmsg_len = CMSG_LEN(sizeof(uint32_t)); *(__u32 *) CMSG_DATA(cmsg) = ALG_OP_ENCRYPT; // 设置IV cmsg = CMSG_NXTHDR(&msg, cmsg); assert(cmsg != NULL); cmsg->cmsg_level = SOL_ALG; cmsg->cmsg_type = ALG_SET_IV; iv = (void *)CMSG_DATA(cmsg); iv->ivlen = 12; memcpy(iv->iv, initVector, 12); cmsg->cmsg_len = CMSG_LEN(sizeof(struct af_alg_iv) - sizeof(iv->iv) + iv->ivlen); // 设置AAD长度 uint32_t *assoclen = NULL; cmsg = CMSG_NXTHDR(&msg, cmsg); assert(cmsg != NULL); cmsg->cmsg_level = SOL_ALG; cmsg->cmsg_type = ALG_SET_AEAD_ASSOCLEN; cmsg->cmsg_len = CMSG_LEN(sizeof(*assoclen)); assoclen = (void *) CMSG_DATA(cmsg); *assoclen = (uint32_t)aadSize; // 发送包含AAD的初始消息 int send_result = sendmsg(openfd, &msg, MSG_MORE); if(send_result < 0){ perror("sendmsg failed"); } assert(send_result > 0);
额外注意事项
- 确认硬件加速器驱动支持
gcm(aes)的AEAD模式,可通过cat /proc/crypto | grep -A10 -B2 "gcm(aes)"查看驱动注册信息。 - 后续需发送明文数据并接收密文+标签,发送明文时若为最后一段需去掉
MSG_MORE标志。
内容的提问来源于stack exchange,提问作者td3614
相关产品推荐
相关产品推荐

