SGX实验报告
一.实验目标
了解采用SGX可信任环境后对应用和目标主机产生的性能影响有多少。
二.实验准备
Microsoft Window10 21H2版本主机一台,
处理器:Intel Core(TM)i5-9500F CPU@3.00GHZ
64位操作系统,内存16GB
代码编译环境:vs2015专业版或者Clion2021
SGX插件相关版本
Intel ME版本:ME_SW_1909.12.0.1237
SDK版本:Intel SGX SDK for Windows v2.12.100.4
PSW版本:Intel SGX PSW for Windows v2.12.100.4
三.实验过程
3.1 不使用SGX插件运行相关计算程序
小程序:计算一万以内的素数,(循环10000次)
程序源码:
- //
- // Created by hudengfeng on 2023/1/9.
- //
- #include <iostream>
- #include <time.h>
- using namespace std;
- // 计算10000以内的素数
- void calculate_prime(){
- int i,j,k=0;//i是2-10000待确认是否为素数的数,j表示i的因子,k表示素数的个数
- for(i=2;i<10000;i++){
- for(j=2;j*j<=i;j++){
- if(i%j==0)//判断i是否能被1和本身以外的数整除,%表示求余
- break;//break跳出第二个for循环
- }
- if(j*j>i){
- cout<<i<<" ";
- k++;//每增加一个素数k就加1
- if(k%10==0) //一行打印10个数之后换行
- {
- cout<<endl;
- }
- }
- }
- }
- void exe(){
- clock_t start, finish;
- double duration;
- start = clock();
- for (int j = 0; j < 10000; ++j) {
- calculate_prime();
- }
- finish = clock();
- duration = (double)(finish - start) / CLOCKS_PER_SEC;
- cout<<endl;
- cout<<"计算累计用时:"<<duration<<"秒"<<endl;
- }
- int main(){
- // cout << "hello world!"<<endl;
- exe();
- return 0;
- }
正常情况cpu使用率:20%(均值)
运行程序cpu使用率:70%(均值)
代码运行结果(10次)
11.732s、13.635s、16.017s、12.544s、14.327s
11.515s、14.301s、12.988s、15.251s、12.677s
均值:13.499s
3.2 使用SGX插件运行相关计算程序
基本原理:
SGX程序分为两部分,一部分是app应用,也就是不可信区,一部分是enclave应用,也就是可信区,非可信区只能通过 ECALL 函数调用可信区内的函数,可信区只能通过 OCALL 函数调用非可信区的函数,ECALL 函数和 OCALL 函数通过 EDL 文件声明。
程序目录结构:
App 目录内为不可信区域代码,包括 main 入口、OCALL 函数内具体逻辑代码等等。
Enclave 目录为可信区域代码,包括 ECALL 函数内具体逻辑代码实现。
Enclave.lds:EDL(Enclave Description Language) 文件。
Enclave_private.pem:enclave.so 的签名私钥。
Enclave.config.xml:Enclave 配置文件,如堆栈大小、是否可等。
Enclave.h & Enclave.cpp:应用安全区代码实现。
Include目录是不可信代码和可信代码共享的头文件。
在app程序中通过ecall函数调用enclave程序的calculate函数来计算结果,然后把计算的结果通过ocall函数返回给app程序,然后app程序把结果打印出来。
编译运行:
1.通过 sgx_edger8r 工具在 App/ 目录下生成不可信代码(Enclave_u.c 和 Enclave_u.h),这部分生成代码主要会调用 ECALL (sgx_ecall);
2.编译不可信部分 Binary: app;
3.通过sgx_edger8r 工具在 Enclave/ 目录下生成可信代码(Enclave_t.c 和 Enclave_t.h);
4.编译可信动态链接库(enclave.so);
5.通过sgx_sing工具签名可信动态链接库(enclave.signed.so);
6.结束。
编译后的代码目录结构:
实验结果:
正常情况cpu使用率:20%(均值)
运行程序cpu使用率:80%(均值)
代码运行结果(10次)
17.496s、12.854s、14.327s、15.635s、14.324s
12.432s、11.543s、15.398s、18.534s、13.264s
均值:14.580s
3.3 enclave安全区多次切换
核心程序源码:
App.cpp
- #include <stdio.h>
- #include <string.h>
- #include <assert.h>
- #include <time.h>
- # include <unistd.h>
- # include <pwd.h>
- # define MAX_PATH FILENAME_MAX
- #include "sgx_urts.h"
- #include "App.h"
- #include "Enclave_u.h"
- using namespace std;
- /* Global EID shared by multiple threads */
- sgx_enclave_id_t global_eid = 0;
- int initialize_enclave(void)
- {
- sgx_status_t ret = SGX_ERROR_UNEXPECTED;
- /* 调用 sgx_create_enclave 创建一个 Enclave 实例 */
- /* Debug Support: set 2nd parameter to 1 */
- ret = sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, NULL, NULL, &global_eid, NULL);
- if (ret != SGX_SUCCESS) {
- printf("Failed to create enclave, ret code: %d\n", ret);
- return -1;
- }
- return 0;
- }
- /* 应用程序入口 */
- int SGX_CDECL main(int argc, char *argv[])
- {
- (void)(argc);
- (void)(argv);
- clock_t start, finish;
- double duration;
- start = clock();
- /* 创建并初始化 Enclave */
- if(initialize_enclave() < 0){
- printf("Enter a character before exit ...\n");
- getchar();
- return -1;
- }
- /* ECALL 调用 */
- /*计算10000以内的素数*/
- for (int i = 0; i < 10; ++i) {
- ecall_calculate_from_enclave(global_eid);
- }
- finish = clock();
- duration = (double)(finish - start) / CLOCKS_PER_SEC;
- cout<<"计算累计用时:"<<duration<<"秒"<<endl;
- /* 销毁 Enclave */
- sgx_destroy_enclave(global_eid);
- printf("Info: SampleEnclave successfully returned.\n");
- printf("Enter a character before exit ...\n");
- getchar();
- return 0;
- }
Enclave.cpp
- void ecall_calculate_from_enclave(){
- for (int j = 0; j < 1000; ++j) {
- calculate_prime();
- }
- }
由以上App.cpp(51-53行)程序可以看出,还是计算10000以内的素数(10000次),但是Enclave.cpp当中只计算了1000次。app.cpp当中有10次循环调用ecall函数
实验结果:
正常情况cpu使用率:20%(均值)
运行程序cpu使用率:84%(均值)
代码运行结果(10次)
22.065s、24.905s、25.687s、21.522s、18.417s
21.592s、20.666s、21.845s、21.499s、18.457s
均值:21.666s
3.4 enclave的epc内存测试
首先修改编译器设置,默认堆栈区大小是1M,如果不想使用堆栈,可在全局区使用大数组,前面加上static即可。需要在图形化界面修改堆栈保留大小这个字段。单位是bit,这里改成256MB,也就是256*1024*1024*8。也可在CMakeLists.txt添加下面2行,就可以达到修改堆栈内存大小的效果。
MATH(EXPR stack_size "256*1024*1024")单位是字节
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--stack,${stack_size}")
也可通过图形化界面修改,在vs2015在项目的属性,找到链接器的系统这一栏,
3.4.1 不使用enclave单独跑带有大数组的程序
在3.4.1执行函数中新增代码(5-10行)
- void exe(){
- clock_t start, finish;
- double duration;
- start = clock();
- int a[4096][4096] = {0};
- int b[4096][4096] = {1};
- a[0][0] = 1;
- size_t num = sizeof(a);
- a[0][1] = num;
- b[0][0] = a[0][1];
- for (int j = 0; j < 10000; ++j) {
- calculate_prime();
- }
- finish = clock();
- duration = (double)(finish - start) / CLOCKS_PER_SEC;
- cout<<endl;
- cout<<"计算累计用时:"<<duration<<"秒"<<endl;
- }
申请了一个两个4096*4096的int类型大数组,初始化值为0,一个大数组内存应该是4*4*4=96MB,两个是192MB,超过了128MB,然后开始跑程序。
实验结果:
正常情况cpu使用率:20%(均值)
运行代码程序后cpu使用率:84%(均值)
代码运行结果(10次)
17.744s、16.946s、20.974s、17.409s、17.022s
20.746s、16.785s、21.114s、18.742s、18.965s
均值:18.645s
3.4.2 使用enclave跑带有大数组的程序
将上述带有大数组的代码复制到Enclave.cpp当中(写在循环外面),
核心代码:
- void ecall_calculate_from_enclave(){
- int a[4096][4096] = {0};
- int b[4096][4096] = {1};
- a[0][0] = 1;
- size_t num = sizeof(a);
- a[0][1] = num;
- b[0][0] = a[0][1];
- for (int j = 0; j < 10000; ++j) {
- calculate_prime();
- }
- }
实验结果:
正常情况cpu使用率:20%(均值)
运行代码程序后cpu使用率:90%(均值)
代码运行结果(10次)
26.264s、26.043s、24.434s、28.206s、23.204s
22.236s、26.238s、25.232s、23.364s、24.652s
均值:24.987s
四.实验结论
通过上述实验可以发现使用SGX安全插件的app应用来计算10000以内的素数(10000次)用的时间比不使用插件要多,cpu使用率也要高一些,但是性能损耗在5%到10%之间,性能损耗可以接受。如果频繁使用ecall函数或者ocall函数,在可信区和非可信区之间进行切换,会有比较明显的性能消耗,性能损耗在20%以上。当epc内存过大也会明显影响主机的性能。性能损耗20%以上。