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

文章目录

  • 一.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分把,感谢各位大佬支持!

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PMBOK® 第六版 结束项目或阶段

目录 读后感—PMBOK第六版 目录 不论是阶段的收尾还是项目整体的收尾&#xff0c;都应是令人振奋的事。然而&#xff0c;在实际生活中&#xff0c;收尾工作却相当艰难。会遭遇负责人调离、换任&#xff0c;导致不再需要已购产品&#xff1b;项目收尾时对照招标文件或合同&…

基于python的房价多元线性回归分析

1.导入必要的库 import pandas as pd import numpy as np import statsmodels.api as sm from sklearn.model_selection import train_test_split from sklearn.metrics import r2_score import matplotlib.pyplot as plt # 忽略Matplotlib的警告&#xff08;可选&…

SpringBoot实现文章点赞功能

提示&#xff1a;今日是2024年的6月30日&#xff0c;未来的你看到这篇文章&#xff0c;希望你依旧快乐 文章目录 前言 首先在这里前缀部分我就不做要求了,比如说登录信息什么的 数据库表格 这里实现点赞功能&#xff0c;主要是围绕论坛项目完成的 user_info代表用户信息表 for…

20240630每日一题-组合数学-平均分组问题

更多资源请关注纽扣编程微信公众号 将6个小球&#xff0c;其中1个红球&#xff0c;2个黑球&#xff0c;3个白球拍成一列&#xff0c;相同颜色的球没区别&#xff0c;那么有多少种排法&#xff1f; 答案 60种 分析 相同颜色的小球可以看作平均分组&#xff0c;去除对应排序的…

Zookeeper:Zookeeper JavaAPI操作与分布式锁

文章目录 一、Zookeeper JavaAPI操作1、Curator介绍2、创建、查询、修改、删除节点3、Watch事件监听 二、Zookeeper分布式锁原理 一、Zookeeper JavaAPI操作 1、Curator介绍 Curator是Apache Zookeeper的Java客户端。常见的Zookeeper Java API&#xff1a; 原生Java API。ZkC…

基于PHP的酒店管理系统(改进版)

有需要请加文章底部Q哦 可远程调试 基于PHP的酒店管理系统(改进版) 一 介绍 此酒店管理系统(改进版)基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端jquery插件美化。系统角色分为用户和管理员。系统在原有基础上增加了注册登录注销功能&#xff0c;增加预订房间图片…

临时文件上传系统Plik

什么是 Plik &#xff1f; Plik 是一个基于 Go 语言的可扩展且用户友好的临时文件上传系统&#xff08;类似于 Wetransfer&#xff09;。 软件主要特点&#xff1a; 强大的命令行客户端易于使用的 Web 用户界面多个数据后端&#xff1a;文件、OpenStack Swift、S3、Google Clo…

Swift中的二分查找:全面指南

Swift中的二分查找&#xff1a;全面指南 简介 二分查找是计算机科学中的经典算法&#xff0c;被广泛用于在已排序的数组中高效地搜索目标值。与线性查找逐个检查每个元素不同&#xff0c;二分查找不断将搜索区间减半&#xff0c;因此在处理大数据集时要快得多。 在这篇博客中…

java基于ssm+jsp 固定资产管理系统

1前台首页功能模块 固定资产管理系统&#xff0c;在系统首页可以查看首页、设备信息、论坛信息、我的、跳转到后台等内容&#xff0c;如图1所示。 图1前台首页功能界面图 注册&#xff0c;在注册页面可以填写用户名、密码、姓名、性别、头像、身份证、手机等详细内容&#xff…

基于Ollama Python的本地多模态大模型

0&#xff0c;背景 最近测试Ollama&#xff0c;发现之前直接下载开源模型在我电脑上都跑不动的模型&#xff0c;居然也能运行了&#xff08;AMD 7840HS核显/32GB内存&#xff09;&#xff0c;突发奇想那些多模态大模型能不能基于Python接口使用&#xff0c;所以决定尝试一下。…

Qt之Pdb生成及Dump崩溃文件生成与调试(含注释和源码)

文章目录 一、Pdb生成及Dump文件使用示例图1.Pdb文件生成2.Dump文件调试3.参数不全Pdb生成的Dump文件调试 二、个人理解1.生成Pdb文件的方式2.Dump文件不生产的情况 三、源码Pro文件mian.cppMainWindowUi文件 总结 一、Pdb生成及Dump文件使用示例图 1.Pdb文件生成 下图先通过…

Springboot+vue电商平台

管理员权限操作的功能包括管理商家&#xff0c;管理商家星级信息&#xff0c;管理用户&#xff0c;管理商品等。 商家权限操作的功能包括管理商品&#xff0c;回复商品评价&#xff0c;管理商品订单等。 用户权限操作的功能包括查看商家&#xff0c;购买商品&#xff0c;提交…

Django之邮箱注册

目录 一、邮箱验证-环境搭建 1.1、注册流程 1.2、环境搭建 二、封装工具类 三、发送邮件接口开发 四、用户调用发送邮件接口 4.1、Fetch API 4.1.1、GET请求 4.1.2、POST请求 五、完成注册功能 一、邮箱验证-环境搭建 1.1、注册流程 1.2、环境搭建 创建项目 django-a…

Variables Reference for vscode

Predefined variables Visual Studio Code 支持在调试、任务配置文件以及一些特定的设置中使用变量替换。这些变量可以使用 ${variableName} 语法在 launch.json 和 tasks.json 文件的某些键和值字符串中使用。 Predefined variables Visual Studio Code 支持以下预定义变量…

【分布式计算框架 MapReduce】高级编程—多任务数据分析

目录 一、对于 sogou_500w_utf 数据&#xff0c;使用 MapReduce 编程模型完成对以下数据的分析任务。 1. 统计搜索的关键字查询频度&#xff0c;找出搜索次数超过 20 次的关键字的个数。 ① 运行截图 ② 源代码 二、改造 WordCount 程序&#xff0c;使得结果的排序规则为按…

APP逆向 day7 JAVA基础2

一.前言 昨天我们讲了点java基础&#xff0c;大家是不是觉得就特别简单&#xff0c;今天讲点稍微难一丢丢的基础&#xff0c;也就是java基础2.0&#xff0c;今天我要和大家说的内容十分的重要&#xff0c;直接关乎到下一节的内容&#xff0c;所以&#xff0c;好好学&#xff0…

React 打包时如何关闭源代码混淆

React 开发中&#xff0c;使用 npm build 命令进行生产代码打包&#xff0c;为了压缩代码并尽量保证代码的安全性&#xff0c;React 打包时会代码进行压缩和混淆&#xff0c;但是有时我们需要 debug 生产环境的源代码&#xff0c;例如当我们调试 SSR 的项目时&#xff0c;需要禁…

<电力行业> - 《第10课:变电》

1 变电 变电环节&#xff0c;顾名思义就是改变电压的环节&#xff0c;主要是在变电站和变电所完成的。变电站和变电所主要区别在于&#xff1a;变电站比变电所更大。 发电厂的变压器和配电变压器也属于“变电”&#xff0c;但我们在说电网环节时&#xff0c;变电特指电网公司…

Android常用加解密算法总结

Android开发中对于数据的传输和保存一定会使用加密技术&#xff0c;加密算法是最普遍的安保手段&#xff0c;多数情况数据加密后在需要使用源数据时需要再进行解密&#xff0c;但凡是都有例外。下面从可逆加密、不可逆、不纯粹加密三种方式记录一下常见的加解密算法。 加密技术…

计算机毕业设计Thinkphp/Laravel校园体育器材管理系统

校园体育器材管理系统在流畅性&#xff0c;续航能力&#xff0c;等方方面面都有着很大的优势。这就意味着校园体育器材管理系统的设计可以比其他系统更为出色的能力&#xff0c;可以更高效的完成最新的体育器材、器材借用、器材归还、器材损坏、采购入库、器材报废、维修记录等…