【SGX系列教程】(八)Intel-SGX 官方示例分析(SampleCode)——Seal Unseal

news2025/1/19 22:24:02

文章目录

  • 一.Seal Unseal原理介绍
    • 1.1 Intel® SGX supported Sealing Policies
  • 二.源码分析
    • 2.1 README
    • 2.2 重点代码分析
      • 2.2.1 主要代码模块交互流程分析
      • 2.2.2 App/App.cpp
      • 2.2.3 Enclave_Seal/Enclave_Seal.cpp
      • 2.2.4 Enclave_Unseal/Enclave_Unseal.cpp
    • 2.3 总结
  • 三.参考文献
  • 四.感谢支持

    下面将给出一些sgx源码包中的示例SealUnseal分析,从中学习enclave密封与解封和SGX的基本使用方法:关于 SGX 开发运行环境的搭建可参考之前的一篇博客:【SGX系列教程】(一)。

一.Seal Unseal原理介绍

    当enclave被实例化时,当其维护在enclave边界内时,硬件为其数据提供保护(机密性和完整性)。然而,当enclave进程退出时,enclave将被摧毁,在enclave内得到安全的任何数据都将丢失。如果这些数据意味着以后会被重用,那么该enclave必须做出特殊安排,在该飞地之外存储这些数据(主要目的:如何在enclave外持久化安全的存储数据?)。
    如下面的表1显示,EGETKEY提供了对持久性Sealing Keys的访问,飞地软件可以使用这些密钥来加密和完整性保护数据。Intel®SGX对该飞地使用的加密方案没有任何限制。当与平台提供的其他服务结合时,如单调计数器,对数据也有可能进行Replay保护。

在这里插入图片描述

1.1 Intel® SGX supported Sealing Policies

指令集:

    EGETKEY:enclave 使用此指令来访问平台提供的各种不同密钥。每个密钥启用不同的操作(密封、证明)。

说明:

    当一个 enclave 被实例化时,它的代码和数据被保护免被外部访问。但是当它停止时,它的所有数据都将丢失。密封是一种将数据安全地保存在 enclave 之外的方法,例如在硬盘驱动器上。enclave 必须使用 EGETKEY 指令检索其密封密钥,它使用此密钥来加密并确保其数据完整性,使用的算法由 enclave 作者选择。

  • 使用 Enclave 标识符
    密封可以使用 enclave 标识来完成。此时基于 MRENCLAVE 的值进行密钥派生,两个不同的 enclave 具有不同的密钥,同一个 enclave 的两个版本也将有不同的密钥,这会阻止数据的本地迁移。

  • 使用签名者标识符
    也可以使用签名者身份标识符进行密封。这个密钥派生是基于 MRSIGNER 的值,两个不同的 enclave 仍然具有不同的密钥,但是一个 enclave 的两个版本共享同一个密钥并且可以读取密封数据。如果多个 enclave 使用相同的密钥进行签名,则它们都可以读取彼此的数据。

  • 安全版本号 (SVN)
    不允许旧版本的 enclave 读取新版本的 enclave 密封的数据。为了防止它,使用了安全版本号 (SVN)。这是一个计数器,在每次更新影响 enclave 安全性后递增。使用 SVN 派生密钥的方式是,enclave 可以检索与当前或较旧的安全级别相对应的密钥,但不能检索较新的密钥。

二.源码分析

2.1 README

------------------------
Purpose of SealUnseal
------------------------
The project demonstrates sealing/unsealing data between two enclaves.
------------------------------------
How to Build/Execute the Sample Code
------------------------------------
1. Install Intel(R) SGX SDK for Linux* OS
2. Enclave test key(two options):
    a. Install openssl first, then the project will generate a test key<Enclave_private_test.pem> automatically when you build the project.
    b. Rename your test key(3072-bit RSA private key) to <Enclave_private_test.pem> and put it under the <Enclave_Seal> folder.
2. Make sure your environment is set:
    $ source ${sgx-sdk-install-path}/environment
3. Build the project with the prepared Makefile:
    a. Hardware Mode, Debug build:
        $ make
    b. Hardware Mode, Pre-release build:
        $ make SGX_PRERELEASE=1 SGX_DEBUG=0
    c. Hardware Mode, Release build:
        $ make SGX_DEBUG=0
    d. Simulation Mode, Debug build:
        $ make SGX_MODE=SIM
    e. Simulation Mode, Pre-release build:
        $ make SGX_MODE=SIM SGX_PRERELEASE=1 SGX_DEBUG=0
    f. Simulation Mode, Release build:
        $ make SGX_MODE=SIM SGX_DEBUG=0
4. Execute the binary directly:
    $ ./app
5. Remember to "make clean" before switching build mode

-------------------------------------------------
Launch token initialization
-------------------------------------------------
If using libsgx-enclave-common or sgxpsw under version 2.4, an initialized variable launch_token needs to be passed as the 3rd parameter of API sgx_create_enclave. For example,

sgx_launch_token_t launch_token = {0};
sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, launch_token, NULL, &global_eid, NULL);

    根据上面的README,项目SealUnseal演示了在两个enclave之间封装和解封数据的过程。以下是如何构建和执行示例代码的步骤总结:

构建和执行示例代码的步骤:

  1. 安装Intel® SGX SDK for Linux OS
    这是基本的前提条件,确保已正确安装SGX SDK。
  2. 准备Enclave测试密钥(两种选择)
    a. 安装openssl,然后在构建项目时,会自动生成一个测试密钥<Enclave_private_test.pem>
    b. 或者,使用你自己的测试密钥(3072位RSA私钥),将其重命名为<Enclave_private_test.pem>并放在<Enclave_Seal>文件夹下。
  3. 确保sdk环境变量已设置: source ${sgx-sdk-install-path}/environment
  4. 构建项目:根据不同的MODE构建项目。
  5. 执行:./app
  6. 切换build模式时记得make clean
  7. 启动令牌初始化:如果使用的libsgx-enclave-common或sgxpsw版本低于2.4(最近安装的都不会),在调用API sgx_create_enclave时需要传递一个初始化的变量launch_token作为第三个参数。例如:
    sgx_launch_token_t launch_token = {0}; sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, launch_token, NULL, &global_eid, NULL);

2.2 重点代码分析

    SGX工程的整个构建流程在之前的文章中已经给出给出了详细教程:【SGX系列教程】(二)第一个 SGX 程序: HelloWorld,因此在此处仅给出部分重点代码分析,主要讲清楚enclave如何实现密封/解封,其他通用代码不做展开分析。

2.2.1 主要代码模块交互流程分析

    文件目录如下图,主要包括三个文件夹,其中App表示REE侧应用程序,Enclave_Seal表示enclave侧数据密封程序,Enclave_Unseal表示enclave侧数据解封程序。主要通过三个程序之间的交互完成远程认证流程。

在这里插入图片描述

2.2.2 App/App.cpp

// App.cpp : 定义控制台应用程序的入口点
#include <string.h>
#include <assert.h>
#include <fstream>
#include <thread>
#include <iostream>

#include "sgx_urts.h"
#include "Enclave_Seal_u.h"
#include "Enclave_Unseal_u.h"

#include "ErrorSupport.h"

// 定义封装和解封相关的常量
#define ENCLAVE_NAME_SEAL "libenclave_seal.signed.so"
#define ENCLAVE_NAME_UNSEAL "libenclave_unseal.signed.so"
#define SEALED_DATA_FILE "sealed_data_blob.txt"

// 获取文件大小的函数
static size_t get_file_size(const char *filename)
{
    std::ifstream ifs(filename, std::ios::in | std::ios::binary);
    if (!ifs.good())
    {
        std::cout << "无法打开文件 \"" << filename << "\"" << std::endl;
        return -1;
    }
    ifs.seekg(0, std::ios::end);
    size_t size = (size_t)ifs.tellg();
    return size;
}

// 将文件内容读入缓冲区的函数
static bool read_file_to_buf(const char *filename, uint8_t *buf, size_t bsize)
{
    if (filename == NULL || buf == NULL || bsize == 0)
        return false;
    std::ifstream ifs(filename, std::ios::binary | std::ios::in);
    if (!ifs.good())
    {
        std::cout << "无法打开文件 \"" << filename << "\"" << std::endl;
        return false;
    }
    ifs.read(reinterpret_cast<char *> (buf), bsize);
    if (ifs.fail())
    {
        std::cout << "从文件 \"" << filename << "\" 读取失败" << std::endl;
        return false;
    }
    return true;
}

// 将缓冲区内容写入文件的函数
static bool write_buf_to_file(const char *filename, const uint8_t *buf, size_t bsize, long offset)
{
    if (filename == NULL || buf == NULL || bsize == 0)
        return false;
    std::ofstream ofs(filename, std::ios::binary | std::ios::out);
    if (!ofs.good())
    {
        std::cout << "无法打开文件 \"" << filename << "\"" << std::endl;
        return false;
    }
    ofs.seekp(offset, std::ios::beg);
    ofs.write(reinterpret_cast<const char*>(buf), bsize);
    if (ofs.fail())
    {
        std::cout << "写入文件 \"" << filename << "\" 失败" << std::endl;
        return false;
    }
    return true;
}

/* 初始化enclave:
*   调用 sgx_create_enclave 来初始化一个enclave实例
*/
static sgx_status_t initialize_enclave(const char* enclave_path, sgx_enclave_id_t *eid)
{
    sgx_status_t ret = SGX_ERROR_UNEXPECTED;
    /* 调用 sgx_create_enclave 来初始化一个enclave实例 */
    /* 调试支持: 设置第二个参数为1 */
    ret = sgx_create_enclave(enclave_path, SGX_DEBUG_FLAG, NULL, NULL, eid, NULL);
    if (ret != SGX_SUCCESS) {
        return ret;
    }
    return SGX_SUCCESS;
}

// 封装数据并保存到文件的函数
static bool seal_and_save_data()
{
    sgx_enclave_id_t eid_seal = 0;
    // 加载封装enclave
    sgx_status_t ret = initialize_enclave(ENCLAVE_NAME_SEAL, &eid_seal);
    if (ret != SGX_SUCCESS)
    {
        ret_error_support(ret);
        return false;
    }
    // 获取封装数据的大小
    uint32_t sealed_data_size = 0;
    ret = get_sealed_data_size(eid_seal, &sealed_data_size); // 获取封装数据大小的enclave调用
    if (ret != SGX_SUCCESS)
    {
        ret_error_support(ret);
        sgx_destroy_enclave(eid_seal);
        return false;
    }
    else if(sealed_data_size == UINT32_MAX)
    {
        sgx_destroy_enclave(eid_seal);
        return false;
    }
    
    uint8_t *temp_sealed_buf = (uint8_t *)malloc(sealed_data_size); // 分配内存来存储封装的数据
    if(temp_sealed_buf == NULL)
    {
        std::cout << "内存不足" << std::endl;
        sgx_destroy_enclave(eid_seal);
        return false;
    }
    sgx_status_t retval;
    ret = seal_data(eid_seal, &retval, temp_sealed_buf, sealed_data_size); // 调用封装数据的enclave,ECALL函数
    if (ret != SGX_SUCCESS)
    {
        ret_error_support(ret);
        free(temp_sealed_buf);
        sgx_destroy_enclave(eid_seal);
        return false;
    }
    else if( retval != SGX_SUCCESS)
    {
        ret_error_support(retval);
        free(temp_sealed_buf);
        sgx_destroy_enclave(eid_seal);
        return false;
    }
    // 保存封装的blob数据
    if (write_buf_to_file(SEALED_DATA_FILE, temp_sealed_buf, sealed_data_size, 0) == false)
    {
        std::cout << "无法将封装数据blob保存到 \"" << SEALED_DATA_FILE << "\"" << std::endl;
        free(temp_sealed_buf);
        sgx_destroy_enclave(eid_seal);
        return false;
    }
    free(temp_sealed_buf); // 释放内存
    sgx_destroy_enclave(eid_seal); // 销毁enclave实例
    std::cout << "封装数据成功。" << std::endl;
    return true;

}

// 读取并解封数据的函数
static bool read_and_unseal_data()
{
    sgx_enclave_id_t eid_unseal = 0;
    // 加载解封enclave
    sgx_status_t ret = initialize_enclave(ENCLAVE_NAME_UNSEAL, &eid_unseal);
    if (ret != SGX_SUCCESS)
    {
        ret_error_support(ret);
        return false;
    }
    // 从文件中读取封装的blob数据
    size_t fsize = get_file_size(SEALED_DATA_FILE);
    if (fsize == (size_t)-1)
    {
        std::cout << "无法获取文件 \"" << SEALED_DATA_FILE << "\" 大小" << std::endl;
        sgx_destroy_enclave(eid_unseal);
        return false;
    }
    uint8_t *temp_buf = (uint8_t *)malloc(fsize);
    if(temp_buf == NULL)
    {
        std::cout << "内存不足" << std::endl;
        sgx_destroy_enclave(eid_unseal);
        return false;
    }
    if (read_file_to_buf(SEALED_DATA_FILE, temp_buf, fsize) == false)
    {
        std::cout << "无法从文件 \"" << SEALED_DATA_FILE << "\" 读取封装数据blob" << std::endl;
        free(temp_buf);
        sgx_destroy_enclave(eid_unseal);
        return false;
    }
    // 解封封装的blob数据
    sgx_status_t retval;
    ret = unseal_data(eid_unseal, &retval, temp_buf, fsize); // 调用解封数据的enclave,ECALL函数
    if (ret != SGX_SUCCESS)
    {
        ret_error_support(ret);
        free(temp_buf);
        sgx_destroy_enclave(eid_unseal);
        return false;
    }
    else if(retval != SGX_SUCCESS)
    {
        ret_error_support(retval);
        free(temp_buf);
        sgx_destroy_enclave(eid_unseal);
        return false;
    }
    free(temp_buf); // 释放内存
    sgx_destroy_enclave(eid_unseal); // 销毁enclave实例
    std::cout << "解封成功。" << std::endl;
    return true;
}

int main(int argc, char* argv[])
{
    (void)argc, (void)argv; // 消除未使用参数的警告
    // Enclave_Seal: 封装秘密并将数据blob保存到文件
    if (seal_and_save_data() == false)
    {
        std::cout << "无法封装秘密并将其保存到文件。" << std::endl;
        return -1;
    }
    // Enclave_Unseal: 从文件中读取数据blob并解封
    if (read_and_unseal_data() == false)
    {
        std::cout << "无法解封数据blob。" << std::endl;
        return -1;
    }
    return 0;
}

代码功能分析:

  1. 初始化与配置:
    代码包含初始化SGX enclave所需的头文件和库文件,并针对封装和解封功能定义了一些常量如ENCLAVE_NAME_SEALENCLAVE_NAME_UNSEAL

  2. 文件操作函数:
    get_file_size:获取指定文件的大小。
    read_file_to_buf:将文件内容读入到指定的缓冲区中。
    write_buf_to_file:将缓冲区的内容写入到指定的文件中。

  3. 封装数据并保存到文件的函数(seal_and_save_data):封装数据并保存到文件的函数,具体步骤如下:

  • 使用 initialize_enclave 初始化一个封装用的enclave,得到封装过程所需的enclave ID eid_seal
  • 调用 get_sealed_data_size 获取封装数据的大小。
  • 分配内存来临时存储封装数据 temp_sealed_buf
  • 使用 seal_data ECALL封装数据,并将结果存储在临时缓冲区中。
  • 将临时缓冲区中的封装数据复制到外部缓冲区 sealed_blob
  • 将缓冲区中的封装数据写入文件 SEALED_DATA_FILE
  • 释放临时缓冲区、销毁enclave实例并输出封装成功的信息。
  1. 读取并解封数据的函数(read_and_unseal_data):读取并解封数据的函数,具体步骤如下:
  • 使用 initialize_enclave 初始化一个解封用的enclave,得到解封过程所需的enclave ID eid_unseal
  • 使用 get_file_size 获取封装数据文件的大小。
  • 分配内存来临时存储读取的封装数据 temp_buf
  • 将封装数据文件中的内容读入临时缓冲区 temp_buf
  • 使用 unseal_data ECALL函数解封数据,并检查返回状态。
  • 释放临时缓冲区、销毁enclave实例并输出解封成功的信息。
  1. 主函数main执行以下操作:
  • 通过上述 seal_and_save_data 封装秘密并将数据blob保存到文件,如果失败则输出错误信息并返回-1。
  • 通过上述 read_and_unseal_data 从文件中读取数据blob并解封,如果失败则输出错误信息并返回-1。
  • 程序成功执行完所有操作后返回0。

    总的来说,App.cpp中的代码展示了一个简单的封装和解封数据的过程。首先通过封装数据并保存到文件,再通过读取文件内容并解封数据,验证数据封装和解封的完整性和安全性。整个过程主要包括初始化enclave、数据封装、文件操作、数据解封等关键环节。

2.2.3 Enclave_Seal/Enclave_Seal.cpp

#include "Enclave_Seal_t.h"
#include "sgx_trts.h"
#include "sgx_tseal.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"

// 待加密的数据
char encrypt_data[BUFSIZ] = "Data to encrypt";
// 附加验证数据
char aad_mac_text[BUFSIZ] = "aad mac text";
// 获取封装数据的大小
uint32_t get_sealed_data_size()
{
    // 计算封装数据的大小
    return sgx_calc_sealed_data_size((uint32_t)strlen(aad_mac_text), (uint32_t)strlen(encrypt_data));
}

// 封装数据函数
sgx_status_t seal_data(uint8_t* sealed_blob, uint32_t data_size)
{
    // 计算封装数据的大小
    uint32_t sealed_data_size = sgx_calc_sealed_data_size((uint32_t)strlen(aad_mac_text), (uint32_t)strlen(encrypt_data));
    // 如果计算出来的封装数据大小为最大值,表示发生了错误
    if (sealed_data_size == UINT32_MAX)
        return SGX_ERROR_UNEXPECTED;
    // 如果封装数据大小超过传入的buffer大小,则返回参数错误
    if (sealed_data_size > data_size)
        return SGX_ERROR_INVALID_PARAMETER;
    // 分配内存用于临时存储封装数据
    uint8_t *temp_sealed_buf = (uint8_t *)malloc(sealed_data_size);
    // 如果内存分配失败,返回内存不足错误
    if(temp_sealed_buf == NULL)
        return SGX_ERROR_OUT_OF_MEMORY;
    // 封装数据并存储在临时缓冲区中
    sgx_status_t  err = sgx_seal_data(
        (uint32_t)strlen(aad_mac_text), // 附加验证数据的长度
        (const uint8_t *)aad_mac_text,  // 附加验证数据
        (uint32_t)strlen(encrypt_data), // 待封装的数据长度
        (uint8_t *)encrypt_data,        // 待封装的数据
        sealed_data_size,               // 封装数据的大小
        (sgx_sealed_data_t *)temp_sealed_buf // 临时存储封装数据的缓冲区
    );
    // 如果封装成功,将封装的数据复制到外部缓冲区
    if (err == SGX_SUCCESS)
    {
        memcpy(sealed_blob, temp_sealed_buf, sealed_data_size);
    }
    // 释放临时缓冲区的内存
    free(temp_sealed_buf);
    // 返回封装操作的结果
    return err;
}

代码功能分析

  1. 获取封装数据的大小:
    get_sealed_data_size函数通过调用sgx_calc_sealed_data_size计算封装数据的大小,并返回该大小。其中,sgx_calc_sealed_data_size根据附加验证数据的长度和待封装数据的长度进行计算。
  2. 封装数据,seal_data函数执行实际的数据封装操作:
  • 首先计算封装数据的大小,并进行错误检查,如封装数据大小是否为最大值,或者是否超过传入的缓冲区大小。
  • 为临时存储封装数据分配内存,如果内存不足则返回错误。
  • 调用sgx_seal_data函数进行数据封装,将结果存储在临时缓冲区中。该函数会将附加验证数据、待封装数据和封装数据大小传递给enclave。
  • 如果封装成功,则将临时缓冲区中的封装数据复制到传入的外部缓冲区sealed_blob中。
  • 最后释放临时缓冲区的内存,并返回封装操作的结果状态码。

    整体而言,这段代码的功能是实现了在SGX enclave内对数据的封装操作,并将封装后的数据通过外部缓冲区返回。封装操作会对数据进行加密和生成验证信息,以确保数据的安全性和完整性。

  • Enclave_Seal.edl
enclave {
    from "sgx_tstdc.edl" import *;
    trusted {
        /* define ECALLs here. */
		public uint32_t get_sealed_data_size();
		public sgx_status_t seal_data([out, size=data_size] uint8_t* sealed_blob, uint32_t data_size);
    };
    untrusted {
        /* define OCALLs here. */
    };
};

2.2.4 Enclave_Unseal/Enclave_Unseal.cpp

#include "Enclave_Unseal_t.h"

#include "sgx_trts.h"
#include "sgx_tseal.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"

// 用于比较的原始秘密数据,解封后用于比较以确定数据的一致性
char encrypt_data[BUFSIZ] = "Data to encrypt";
char aad_mac_text[BUFSIZ] = "aad mac text";

// 解封数据函数,ECALL函数
sgx_status_t unseal_data(const uint8_t *sealed_blob, size_t data_size)
{
    // 获取附加验证数据(MAC)的长度
    uint32_t mac_text_len = sgx_get_add_mac_txt_len((const sgx_sealed_data_t *)sealed_blob);
    // 获取解密后数据的长度
    uint32_t decrypt_data_len = sgx_get_encrypt_txt_len((const sgx_sealed_data_t *)sealed_blob);
    // 如果获取到的长度为最大值,表示发生了错误
    if (mac_text_len == UINT32_MAX || decrypt_data_len == UINT32_MAX)
        return SGX_ERROR_UNEXPECTED;
    // 如果长度超过传入的数据大小,返回参数错误
    if(mac_text_len > data_size || decrypt_data_len > data_size)
        return SGX_ERROR_INVALID_PARAMETER;
    // 分配内存用于存储解封后的附加验证数据
    uint8_t *de_mac_text =(uint8_t *)malloc(mac_text_len);
    if(de_mac_text == NULL)
        return SGX_ERROR_OUT_OF_MEMORY;
    // 分配内存用于存储解封后的数据
    uint8_t *decrypt_data = (uint8_t *)malloc(decrypt_data_len);
    if(decrypt_data == NULL)
    {
        free(de_mac_text);
        return SGX_ERROR_OUT_OF_MEMORY;
    }

    // 调用sgx_unseal_data解封数据,并将解封后的数据存储在分配的缓冲区中
    sgx_status_t ret = sgx_unseal_data(
        (const sgx_sealed_data_t *)sealed_blob, // 封装数据的指针
        de_mac_text,                            // 存储解封后的附加验证数据
        &mac_text_len,                          // 输出的附加验证数据长度
        decrypt_data,                           // 存储解封后的数据
        &decrypt_data_len                       // 输出的解封后数据长度
    );
    // 如果解封操作失败,释放内存并返回错误状态
    if (ret != SGX_SUCCESS)
    {
        free(de_mac_text);
        free(decrypt_data);
        return ret;
    }
    // 比较解封后的附加验证数据和原始附加验证数据,以及解封后的数据和原始数据
    // 如果不一致,则返回意外错误
    if (memcmp(de_mac_text, aad_mac_text, strlen(aad_mac_text)) || memcmp(decrypt_data, encrypt_data, strlen(encrypt_data)))
    {
        ret = SGX_ERROR_UNEXPECTED;
    }
    // 释放内存
    free(de_mac_text);
    free(decrypt_data);
    // 返回解封操作的结果状态
    return ret;
}

代码功能分析

  1. 解封数据函数(unseal_data):解封并验证封装数据的函数,具体步骤如下:
  • 获取解封数据长度:
    使用 sgx_get_add_mac_txt_len 获取封装数据中附加验证数据的长度。
    使用 sgx_get_encrypt_txt_len 获取封装数据中解密后数据的长度。
    如果这两个长度中的任意一个为 UINT32_MAX,则表示发生了错误,返回 SGX_ERROR_UNEXPECTED
  • 参数检查:
    检查 mac_text_lendecrypt_data_len 是否大于传入的 data_size,如果是则返回 SGX_ERROR_INVALID_PARAMETER
  • 分配内存:
    为存储解封后的附加验证数据和解密数据分配内存。如果内存分配失败,返回 SGX_ERROR_OUT_OF_MEMORY
  • 解封数据:
    调用 sgx_unseal_data 进行数据解封,并将结果存储在分配的缓冲区中。如果解封操作失败,释放内存并返回相应的错误状态。
  • 数据比较:
    比较解封后的附加验证数据 de_mac_text 与原始附加验证数据 aad_mac_text,以及解封后的数据 decrypt_data 与原始数据 encrypt_data。如果数据不一致,返回 SGX_ERROR_UNEXPECTED
  • 内存释放:
    释放 de_mac_textdecrypt_data 缓冲区的内存,并返回解封操作的结果状态。

    总体而言,这段代码实现了对封装数据的解封操作,并对解封后的数据进行验证,以确保数据的完整性和安全性。通过获取封装数据的附加验证数据和解密数据长度,并分配相应的内存来存储解封后的数据,代码完成了数据的解封、验证和清理工作。

  • Enclave_Unseal.edl
enclave {
    from "sgx_tstdc.edl" import *;
    include "stdint.h"
    trusted {
        /* define ECALLs here. */
		public sgx_status_t unseal_data([in, size=data_size] const uint8_t *sealed_blob, size_t data_size);
    };

    untrusted {
        /* define OCALLs here. */
    };
};

2.3 总结

Enclave 密封与解封的工程实现流程总结:
    App.cppEnclave_Seal.cppEnclave_Unseal.cpp 三个文件为主要功能文件,实现了在两个SGX enclave之间的密封和解封操作。以下是整个工程的实现流程总结:

  1. 封装流程:封装流程主要涉及 App.cppEnclave_Seal.cpp 文件:
  • App.cpp:
    Initialize Enclave:调用 initialize_enclave 函数初始化一个封装用的enclave实例。
    Seal Data:通过 seal_and_save_data 函数,调用封装enclave中的 seal_data 函数执行数据封装,并将封装后的数据保存到文件中。
    Write to File:使用 write_buf_to_file 函数将封装后的数据写入到文件 SEALED_DATA_FILE 中。

  • Enclave_Seal.cpp:
    Calculate Sealed Data Size:通过 sgx_calc_sealed_data_size 计算封装数据所需的大小。
    Seal Data:使用 sgx_seal_data 执行数据封装,将待封装的数据和附加验证数据一起进行加密并生成验证信息。
    Copy Sealed Data:将封装后的数据复制到提供的缓冲区 sealed_blob 中。

  1. 解封流程:解封流程主要涉及 App.cppEnclave_Unseal.cpp 文件:
  • App.cpp:
    Initialize Enclave:调用 initialize_enclave 函数初始化一个解封用的enclave实例。
    Read File:通过 read_and_unseal_data 函数,读取封装数据文件 SEALED_DATA_FILE 并将数据加载到缓冲区中。
    Unseal Data:调用解封enclave中的 unseal_data 函数执行数据解封。
  • Enclave_Unseal.cpp:
    Get Sealed Data Sizes:通过 sgx_get_add_mac_txt_len 和 sgx_get_encrypt_txt_len 获取封装数据中附加验证数据和解密数据的长度。
    Allocate Memory:分配内存用于存储解封后的附加验证数据 de_mac_text 和解密数据 decrypt_data。
    Unseal Data:使用 sgx_unseal_data 函数解封数据,根据解封后数据的验证信息检查数据的完整性。
    Compare Data:将解封后的附加验证数据和解密数据与原始数据进行比较,确保数据未被篡改。
    Free Memory:释放用于存储解封数据的内存。

三.参考文献

  1. https://github.com/intel/linux-sgx/tree/main/SampleCode/SealUnseal
  2. Innovative Technology for CPU Based Attestation and Sealing论文翻译
  3. 基于 CPU 的认证和密封技术

四.感谢支持

    完结撒花!后续将持续输出,形成Intel SGX的系列教程,并结合密码学算法设计更复杂功能。希望看到这里的小伙伴能点个关注,也欢迎志同道合的小伙伴一起广泛交流。
    码字实属不易,如果本文对你有10分帮助,就赏个10分把,感谢各位大佬支持!

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1880906.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Debugging using Visual Studio Code

One of the key features of Visual Studio Code is its great debugging support. VS Code’s built-in debugger helps accelerate your edit, compile, and debug loop. Debugger extensions VS Code 内置了对 Node.js 运行时的调试支持,可以调试 JavaScript、TypeScript…

HDFS学习

3.5 HDFS存储原理 3.5.1 冗余数据保存 作为一个分布式文件系统&#xff0c;为了保证系统的容错性和可用性&#xff0c;HDFS采用了多副本方式对数据进行冗余存储&#xff0c;通常一个数据块的多个副本会被分布到不同的数据节点上。 如图所示&#xff0c;数据块1被分别存放到…

【IVI】CarService启动-Android13

【IVI】CarService启动-Android13 1、CarServiceImpl启动概述2、简要时序图 1、CarServiceImpl启动概述 【IVI】CarService启动&#xff1a; CarServiceHelperService中绑定CarServiceICarImpl初始化各种服务 packages/services/Car/README.md 2、简要时序图

RabbitMQ-交换机的类型以及流程图练习-01

自己的飞书文档:‌‍‬‍‬‍​‍‬​⁠‍​​​‌⁠​​‬‍​​​‬‬‌​‌‌​​&#xfeff;​​​​&#xfeff;‍​‍​‌&#xfeff;⁠‬&#xfeff;&#xfeff;&#xfeff;​RabbitMQ的流程图和作业 - 飞书云文档 (feishu.cn) 作业 图片一张 画rabbit-mq 消息发…

imx6ull/linux应用编程学习(6)jpeg和png的图片显示

1.JPEG图片显示 JPEG&#xff08;Joint Photographic Experts Group&#xff09;是由国际标准组织为静态图像所建立的第一个国际数字图像压缩标准&#xff0c;也是至今一直在使用的、应用最广的图像压缩标准。JPEG 由于可以提供有损压缩&#xff0c;因此压缩比可以达到其他传统…

sqlserver开启CDC

1、背景 由于需要学习flink cdc&#xff0c;并且数据选择sqlserver&#xff0c;所以这里记录sqlserver的cdc开启操作步骤。 2、基础前提 官方介绍地址&#xff1a;https://learn.microsoft.com/zh-cn/sql/relational-databases/track-changes/enable-and-disable-change-dat…

快递物流仓库管理系统java项目springboot和vue的前后端分离系统java课程设计java毕业设计

文章目录 快递物流仓库管理系统一、项目演示二、项目介绍三、部分功能截图四、部分代码展示五、底部获取项目源码&#xff08;9.9&#xffe5;带走&#xff09; 快递物流仓库管理系统 一、项目演示 快递物流仓库管理系统 二、项目介绍 语言: Java 数据库&#xff1a;MySQL 前…

论文阅读《U-KAN Makes Strong Backbone for MedicalImage Segmentation and Generation》

Abstract U-Net 已成为图像分割和扩散概率模型等各种视觉应用的基石。虽然通过结合transformer或 MLP&#xff0c;U-Net 已经引入了许多创新设计和改进&#xff0c;但仍然局限于线性建模模式&#xff0c;而且可解释性不足。为了应对这些挑战&#xff0c;我们的直觉受到了 Kolm…

PotPlayer安装及高分辨率设置

第1步&#xff1a; 下载安装PotPlayer软件 PotPlayer链接&#xff1a;https://pan.baidu.com/s/1hW168dJrLBonUnpLI6F3qQ 提取码&#xff1a;z8xd 第2步&#xff1a; 下载插件&#xff0c;选择系统对应的位数进行运行&#xff0c;该文件不能删除&#xff0c;删除后将失效。 …

云计算HCIE+RHCE学员的学习分享

大一下学期&#xff0c;我从学长嘴里了解到誉天教育&#xff0c;当时准备考RHCE&#xff0c;我也了解了很多培训机构&#xff0c;然后学长强烈给我推荐誉天&#xff0c;我就在誉天报名了RHCE的课程。 通过杨峰老师的教学&#xff0c;我学到了许多Linux知识&#xff0c;也了解了…

【87 backtrader期权策略】基于50ETF期权的covered-call-strategy

前段时间有读者希望能够实现一个期权策略的模板,这段时间通过akshare下载了期权的数据,并进行了清洗,写了一个最简单的期权策略,供大家参考。 策略逻辑: 这是151 trading strategies中的一个期权策略。 买入50ETF基金,手续费按照万分之二计算,一直持有卖出一个最远期的…

Analyze an ORA-12801分析并行 parallel 12801 实际原因

"ORA-06512: at "PKG_P_DATA", line 19639 ORA-06512: at "PKG_P_DATA", line 19595 ORA-06512: at "PKG_P_DATA", line 14471-JOB 调用 -ORA-12801: error signaled in parallel query server P009, instance rac2:dwh2 (2) Error: ORA-12…

基于YOLOv9的PCB板缺陷检测

数据集 PCB缺陷检测&#xff0c;我们直接采用北京大学智能机器人开放实验室数据提供的数据集&#xff0c; 共六类缺陷 漏孔、鼠咬、开路、短路、杂散、杂铜 已经对数据进行了数据增强处理&#xff0c;同时按照YOLO格式配置好&#xff0c;数据内容如下 模型训练 ​ 采用YOLO…

❤ Gitee平台的使用

Gitee平台的使用 文章目录 Gitee平台的使用一、Gitee的注册1、注册2、添加邮箱 二、仓库的创建 和 团队成员的添加1、单击右上角的 **&#xff0b;** 号 、创建仓库2、如下填写即可 三、仓库克隆到本地1、安装好git 和 小乌龟&#xff08;TortoiseGit&#xff09;2、打开仓库 复…

Objective-C使用块枚举的细节

对元素类型的要求 在 Objective-C 中&#xff0c;NSArray 只能存储对象类型&#xff0c;而不能直接存储基本类型&#xff08;例如 int&#xff09;。但是&#xff0c;可以将基本类型封装在 NSNumber 等对象中&#xff0c;然后将这些对象存储在 NSArray 中。这样&#xff0c;en…

IIS在Windows上的搭建

&#x1f4d1;打牌 &#xff1a; da pai ge的个人主页 &#x1f324;️个人专栏 &#xff1a; da pai ge的博客专栏 ☁️宝剑锋从磨砺出&#xff0c;梅花香自苦寒来 目录 一 概念&#xff1a; 二网络…

五、Pentium 微处理器保护模式存储管理,《微机系统》第一版,赵宏伟

一、分段存储管理 Pentium支持分段存储管理、分页存储管理和段页式存储管理。 1.1 分段存储管理的基本思想 一个程序由多个模块组成。 每一个模块都是一个特定功能的独立的程序段。 段式管理&#xff1a;把主存按段分配的存储管理方式。 程序模块→段→段描述符→段描述符…

基于Java校园短期闲置资源置换平台设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f; 感兴趣的可以先收藏起来&#xff0c;…

1.搭建篇——帝可得后台管理系统

目录 前言项目搭建一、搭建后端项目1.初始化项目Maven构建 2.MySQL相关导入sql配置信息 3. Redis相关启动配置信息 4.项目运行 二、 搭建前端项目1.初始化项目2.安装依赖3.项目运行 三、问题 前言 提示&#xff1a;本篇讲解 帝可得后台管理系统 项目搭建 项目搭建 一、搭建后…

【多媒体】Java实现MP4视频播放器【JavaFX】【音视频播放】

在Java中播放视频可以使用多种方案&#xff0c;最常见的是通过Swing组件JFrame和JLabel来嵌入JMF(Java Media Framework)或Xuggler。不过&#xff0c;JMF已经不再被推荐使用&#xff0c;而Xuggler是基于DirectX的&#xff0c;不适用于跨平台。而且上述方案都需要使用第三方库。…