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

如何传输OpenSSL AES 128 GCM标签至Intel SGX端实现Rijndael解密?

AES-128 GCM 客户端加密到SGX端解密的标签传输与实现方案

核心原理

GCM模式的解密依赖三个核心数据:密钥、初始化向量(IV)、认证标签(Tag)。其中密钥是两端预先协商好的,IV和Tag需要客户端加密后随密文一起传输到SGX端——缺少任意一项都会导致解密失败或认证不通过。

客户端(OpenSSL)加密与数据打包步骤

  1. 生成符合GCM标准的随机IV(推荐12字节/96位,这是NIST指定的最优长度,可避免IV重复带来的安全风险)
  2. 初始化AES-GCM加密上下文,设置密钥与IV
  3. 加密明文得到密文
  4. 通过EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag)提取16字节的认证标签
  5. 将IV、密文、标签按固定结构拼接成传输包,推荐结构:
    [IV(12字节)] + [密文(任意长度)] + [Tag(16字节)]
    

客户端代码示例

#include <openssl/evp.h>
#include <stdlib.h>
#include <string.h>

#define AES_KEY_SIZE 16
#define GCM_IV_SIZE 12
#define GCM_TAG_SIZE 16

int aes_gcm_encrypt(const unsigned char *key, const unsigned char *plaintext, int plaintext_len,
                    unsigned char *iv, unsigned char *ciphertext, unsigned char *tag) {
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    int len, ciphertext_len;

    // 生成随机IV
    if (!RAND_bytes(iv, GCM_IV_SIZE)) {
        EVP_CIPHER_CTX_free(ctx);
        return -1;
    }

    // 初始化加密上下文
    if (!EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL) ||
        !EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, GCM_IV_SIZE, NULL) ||
        !EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) {
        EVP_CIPHER_CTX_free(ctx);
        return -1;
    }

    // 加密明文
    if (!EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) {
        EVP_CIPHER_CTX_free(ctx);
        return -1;
    }
    ciphertext_len = len;

    // 完成加密并获取标签
    if (!EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) {
        EVP_CIPHER_CTX_free(ctx);
        return -1;
    }
    ciphertext_len += len;

    if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, GCM_TAG_SIZE, tag)) {
        EVP_CIPHER_CTX_free(ctx);
        return -1;
    }

    EVP_CIPHER_CTX_free(ctx);
    return ciphertext_len;
}

// 打包传输数据:IV + 密文 + Tag
unsigned char* pack_transport_data(unsigned char *iv, unsigned char *ciphertext, int ciphertext_len, unsigned char *tag, int *total_len) {
    *total_len = GCM_IV_SIZE + ciphertext_len + GCM_TAG_SIZE;
    unsigned char *buf = malloc(*total_len);
    if (!buf) return NULL;
    memcpy(buf, iv, GCM_IV_SIZE);
    memcpy(buf + GCM_IV_SIZE, ciphertext, ciphertext_len);
    memcpy(buf + GCM_IV_SIZE + ciphertext_len, tag, GCM_TAG_SIZE);
    return buf;
}

SGX端解密步骤

  1. 从接收的二进制包中拆分数据:
    • 前12字节提取为IV
    • 中间部分为密文(总长度减去12字节IV和16字节Tag的剩余长度)
    • 最后16字节提取为认证标签
  2. 初始化AES-GCM解密上下文,设置密钥与IV
  3. 解密密文
  4. 通过EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag)传入待验证的标签
  5. 调用EVP_DecryptFinal_ex完成解密——此步骤会自动验证标签有效性,验证失败则返回错误

SGX端代码示例

#include "sgx_aes_gcm.h"
#include <string.h>
#include <stdlib.h>

#define AES_KEY_SIZE 16
#define GCM_IV_SIZE 12
#define GCM_TAG_SIZE 16

int aes_gcm_decrypt_in_sgx(const unsigned char *key, unsigned char *transport_buf, int transport_len,
                           unsigned char *plaintext, int *plaintext_len) {
    if (transport_len < GCM_IV_SIZE + GCM_TAG_SIZE) {
        return -1; // 数据长度不足
    }

    // 拆分IV、密文、标签
    unsigned char iv[GCM_IV_SIZE];
    unsigned char tag[GCM_TAG_SIZE];
    int ciphertext_len = transport_len - GCM_IV_SIZE - GCM_TAG_SIZE;
    unsigned char *ciphertext = transport_buf + GCM_IV_SIZE;

    memcpy(iv, transport_buf, GCM_IV_SIZE);
    memcpy(tag, transport_buf + GCM_IV_SIZE + ciphertext_len, GCM_TAG_SIZE);

    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    int len;

    // 初始化解密上下文
    if (!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL) ||
        !EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, GCM_IV_SIZE, NULL) ||
        !EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) {
        EVP_CIPHER_CTX_free(ctx);
        return -1;
    }

    // 解密密文
    if (!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) {
        EVP_CIPHER_CTX_free(ctx);
        return -1;
    }
    *plaintext_len = len;

    // 设置标签并完成解密(自动验证标签)
    if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, GCM_TAG_SIZE, tag) ||
        !EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) {
        EVP_CIPHER_CTX_free(ctx);
        return -2; // 标签验证失败
    }
    *plaintext_len += len;

    EVP_CIPHER_CTX_free(ctx);
    return 0;
}

关键注意事项

  • IV唯一性:每次加密必须使用全新的随机IV,绝不能重复使用同一IV和密钥组合,否则会直接泄露密钥信息
  • 标签长度一致性:固定使用16字节标签,SGX端sgx_aes_gcm.cpp默认采用此长度,避免长度不匹配导致验证失败
  • 二进制传输:IV、密文、标签以原始二进制格式传输即可,无需转码为Base64(除非适配文本协议,但会增加数据体积)
  • 密钥安全:密钥需通过ECDH等安全协议协商交换,绝不能明文传输

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 19:05:23