开发TEE的踩坑之开发TEE

系统:Ubuntu20.04(双系统,非虚拟机)

  • 一、前置说明
    • 1、TEE平台的选择
    • 2、机器间的通信方式
    • 3、程序和数据集的示例
    • 4、结果文件的解密
  • 二、服务器部署
  • 三、客户端部署
  • 四、工程应用

本系列为笔者开发TEE(Trusted Execution Environment,可信执行环境)的系列踩坑文,给广大开发者分享自己所谓的“经验”,希望对大家有帮助。

开发路线为:

  1. 装Ubuntu20.04的双系统(不展开,B站有很多教程)
  2. 配置SGX环境(前提是SGX机器,最好是SGX_2)
  3. 配置PCCS(很蛋疼,英特尔官方Github的步骤也未必行得通)
  4. 开发TEE(花的时间最多)

本篇文章分享开发TEE的踩坑
笔者是在某蚁集团的Occlum的基础上,结合ChatGPT给出的回答去解决途中遇到的问题的

一、前置说明

1、TEE平台的选择

TEE平台有众多选择,在此之前,笔者已在某语的TrustedFlow踩过无数坑了。但奈何若要使用他们的平台开发TEE,需要有可以支持SGX_2的CPU,否则一切都是徒劳,只能用仿真模式,这无异于把程序放在裸机上跑,已与TEE毫无相关;还有一个致命之处是他们例程的角色过于复杂,若要用于实际的落地工程,需要具备良好的密码学功底,并花费大量时间刨出自己所需要的模块为己所用。
基于以上缺陷,笔者最后选择了某蚁集团的Occlum开发TEE。

2、机器间的通信方式

在介绍通信方式之前,首先要明确一点:TEE沙箱是作为服务器(Server),而机构是作为客户端(Client),且二者必须同处一个局域网内,否则是否“可信”要打上问号了。明确角色后,且两台机器同处于一个局域网内,那么通信方式便怎么简单怎么来。
此处笔者以flask(基于Python的Web框架)进行客户端和服务器的通信(该通信方式不含双向远程认证)

3、程序和数据集的示例

对于没接触过Occlum的读者可以模仿这篇文章跑一份程序体验一下。
【注意:机器一定要预先配置好SGX环境,可参考该系列踩坑文的配置SGX环境】
笔者开发TEE的场景是隐私求交,当然目前做的还只是明文求交,但程序确实是在TEE环境(Enclave,飞地)运行的,是可以保证“可信”。
程序语言选用C,之所以不采用Python,是因为求交所需要安装的库和依赖之间有版本冲突不兼容的问题,此处笔者已踩过坑,读者可尝试并留下评论互相学习噢。
进行求交的数据集此处采用经典的乳腺癌数据集:alice和bob.

4、结果文件的解密

若读者有接触过Occlum,相信首次使用一定会遇到读取数据集的路径问题;若还定义了生成结果文件的路径,也肯定会遇到生成结果文件是密文且多个的问题,这些密文文件是固定保存在/occlum_instance/run/mount/__ROOT,如下图:
在这里插入图片描述
笔者已询问过Occlum的官方人员,但回答是使用挂载mount进行解密。笔者至今仍不明白目录挂载与结果文件的解密有何联系,亦没有渠道对这些密文结果文件(里面都是乱码)进行解密,有兴趣的读者可研究一番并留下评论互相学习噢。
基于Occlum的这种生成密文结果的机制,笔者将计就计,绕开这个问题,却依然能输出明文结果并返回给客户端。
读者且保持耐心继续往下浏览。

二、服务器部署

1、起特权模式、映射/dev/sgx和mount文件夹(mount用于在外部宿主机也存储结果文件)、与宿主机的时间同步、映射50054和50055端口号(前者用于通信请求,后者用于被访问结果文件,此处以50054和50055为例)的容器。

sudo docker run -it --privileged -v /dev/sgx:/dev/sgx -v /home/yunqi/mount:/root/mount -v /etc/localtime:/etc/localtime:ro -v /etc/timezone:/etc/timezone:ro -p 50054:50054 -p 50055:50055 <docker镜像源>/occlum:latest-ubuntu20.04

【温馨提示:6月份的时候,由于某些不可抗拒的原因,国内的dockerhub已经禁止访问了,因此读者可以参考该视频,把你需要的docker镜像用Github放在自己的阿里云上】

2、在容器内安装flask库(采用阿里镜像源更快),用于客户端(机构)和服务器(TEE沙箱)间的通信,前面已有介绍。

pip3 install Flask -i https://mirrors.aliyun.com/pypi/simple/

3、用于存放程序的文件夹

mkdir program

4、用于存放服务器的流程代码和自动化指令

mkdir server_file

5、新建用于求交的程序

cd ./program
touch psi.c
vim psi.c

Occlum中运行的程序一般是放在/occlum_instance/image/bin,且由于Occlum的特性,读者不必质疑define的路径

//psi.c#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define FILE1_PATH "/bin/file1.csv"
#define FILE2_PATH "/bin/file2.csv"#define MAX_LINE_LENGTH 1024typedef struct {char id[100];char attributes[900];
} Record;void trim_newline(char *str) {char *newline = strchr(str, '\n');if (newline) {*newline = '\0';}
}int main() {FILE *File1 = fopen(FILE1_PATH, "r");FILE *File2 = fopen(FILE2_PATH, "r");if (!File1 || !File2) {fprintf(stderr, "Error opening file.\n");return 1;}char line[MAX_LINE_LENGTH];Record Records1[1000];Record Records2[1000];int Count1 = 0, Count2 = 0;// Read file1while (fgets(line, MAX_LINE_LENGTH, File1)) {trim_newline(line);char *token = strtok(line, ",");strcpy(Records1[Count1].id, token);token = strtok(NULL, "");if (token != NULL) {strcpy(Records1[Count1].attributes, token);} else {strcpy(Records1[Count1].attributes, "");}Count1++;}fclose(File1);// Read file2while (fgets(line, MAX_LINE_LENGTH, File2)) {trim_newline(line);char *token = strtok(line, ",");strcpy(Records2[Count2].id, token);token = strtok(NULL, "");if (token != NULL) {strcpy(Records2[Count2].attributes, token);} else {strcpy(Records2[Count2].attributes, "");}Count2++;}fclose(File2);// Find intersection and print resultsprintf("The intersection result is as follows\n");for (int i = 0; i < Count1; i++) {for (int j = 0; j < Count2; j++) {if (strcmp(Records1[i].id, Records2[j].id) == 0) {printf("%s,%s,%s\n", Records1[i].id, Records1[i].attributes, Records2[j].attributes);}}}return 0;
}

6、新建存放自动化指令的文件

cd ../server_file
touch commands.txt
vim commands.txt
occlum-gcc -o psi psi.c
mkdir occlum_instance
cd ./occlum_instance
occlum init
cp ../file1.csv ./image/bin
cp ../file2.csv ./image/bin
cp ../psi ./image/bin
occlum build --sgx-mode HW
occlum run /bin/psi

7、新建服务器的流程代码文件

touch task_server.py
vim task_server.py
# task_server.py
from flask import Flask, jsonify, request, send_from_directory
import subprocess
import shutil
import uuid
import os
import csv
import threading
import timeapp = Flask(__name__)
http_server_process = Nonedef start_http_server(): global http_server_processif not http_server_process:# 50055:用于被客户端访问结果文件http_server_process = subprocess.Popen(['python3', '-m', 'http.server', '50055'], cwd="/root/mount")time.sleep(2)def stop_http_server():global http_server_runningif http_server_process:http_server_process.terminate()http_server_process.wait()http_server_process = None@app.route('/execute-task', methods=['POST'])
def execute_task():global http_server_thread, http_server_runningtry:# 生成唯一的任务ID,格式为uuidtask_id = str(uuid.uuid4())# 获取当前时间,并创建以当前时间命名的Occlum工程文件夹current_time = subprocess.check_output("date +'%Y-%m-%d_%H-%M-%S'", shell=True).decode('utf-8').strip()folder_name = f'/root/{current_time}'os.makedirs(folder_name, exist_ok=True)# 拷贝求交的C程序到Occlum工程文件夹source_c_file = '/root/program/psi.c'destination_c_file = os.path.join(folder_name, 'psi.c')shutil.copy(source_c_file, destination_c_file)# 保存客户端发送来的csv数据集到Occlum工程文件夹file1_path = os.path.join(folder_name, 'file1.csv')file2_path = os.path.join(folder_name, 'file2.csv')if 'file1' in request.files:file1 = request.files['file1']file1.save(file1_path)if 'file2' in request.files:file2 = request.files['file2']file2.save(file2_path)# 进入Occlum工程文件夹os.chdir(folder_name)# 读取并执行命令文件中的Occlum指令command_file = '/root/server_file/commands.txt'with open(command_file, 'r') as file:commands = file.readlines()# 使用 `/bin/bash -c` 执行整个命令字符串,并捕获输出command_str = '\n'.join(commands)result =  subprocess.run(f'/bin/bash -c "{command_str}"', shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)# 获取求交C程序的打印输出c_program_output = result.stdout# 找到C程序输出的"The intersection result is as follows"这一行的位置lines = c_program_output.splitlines()start_index = lines.index("The intersection result is as follows") + 1# 提取该行之后的内容output_lines = lines[start_index:]# 将提取的内容写入并保存csv结果文件output_csv_file_name = f'{current_time}_result_psi.csv'output_csv_file = os.path.join("/root/mount", output_csv_file_name)with open(output_csv_file, 'w', newline='') as csvfile:csvwriter = csv.writer(csvfile)for line in output_lines:if line.strip():csvwriter.writerow(line.split(','))# 启动http服务器,以便客户端可以访问TEE沙箱的/root/mount的csv结果文件start_http_server()# 返回任务ID和生成的结果文件名给客户端return jsonify({'task_id': task_id, 'file_name': output_csv_file_name})except Exception as e:return jsonify({'error': str(e)}), 500@app.route('/download/<filename>', methods=['GET'])
def download_file(filename):directory = "/root/mount"response = send_from_directory(directory, filename)stop_http_server()return responseif __name__ == '__main__':# 50054:用于接受通信请求app.run(host='0.0.0.0', port=50054)

三、客户端部署

相较于服务器的部署工作,客户端就显得尤为简洁了,只需做好发送数据集和通信请求的工作就好了。
【注意:服务器和客户端的系统都是Ubuntu20.04】

mkdir client_file
<存放alice和bob的数据集在此处>
touch request_client.py
vim request_client.py
# request_client.py
import requests# 替换为服务器的IP地址和Occlum容器用于接受通信请求的端口号
url = 'http://<服务器的IP地址>:50054/execute-task' 
files = {'file1': open('/home/<用户名>/client_file/alice.csv', 'rb'),'file2': open('/home/<用户名>/client_file/bob.csv', 'rb')
}response = requests.post(url, files=files)if response.status_code == 200:data = response.json()print("Task execution triggered successfully.")print("Task ID:", data['task_id'])print("Generated file name:", data['file_name'])
else:print("Failed to trigger task execution.")print("Error:", response.text)

四、工程应用

做好以上部署工作后,读者们可以开始正式感受TEE了。

1、服务器先运行

python3 task_server.py

2、客户端再运行

python3 request_client.py

3、服务器和客户端的输出分别是
在这里插入图片描述
可以看到服务器已经打开了50055的端口号,等待客户端访问。

在这里插入图片描述
可以看到客户端已经接收到服务器返回的任务ID和结果文件名.

4、此时,在客户端的浏览器可以输入<服务器的IP地址>:50055进入服务器的/root/mount文件夹,查看并下载求交的结果文件,如下图
在这里插入图片描述
5、alice.csvbob.csv的前10行如下
在这里插入图片描述

在这里插入图片描述

求交结果result_psi.csv如下
在这里插入图片描述

6、感兴趣的读者一定要动手尝试一下,毕竟实践是检验真理的唯一标准。本篇开发TEE的基础踩坑文已经十分详细了。

7、此工程代码还有一大优势:
只要服务器一旦执行了python3 task_server.py后,理论上来说客户端是可以无限次向服务器执行求交请求的,服务器可以不再需要人工操作。

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

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

相关文章

【笔记】虚拟机中的主从数据库连接实体数据库成功后的从数据库不同步问题解决方法2

错误&#xff1a; Last_Errno: 1008 Last_Error: Coordinator stopped because there were error(s) in the worker(s). The most recent failure being: Worker 1 failed executing transaction ANONYMOUS at source log mysql-bin.000014, end_log_pos 200275. See error lo…

开放式耳机哪款好一点?开放式耳机科普五款推荐!

“选择开放式耳机真的太难了” “哥&#xff0c;怎么才能选到心仪的开放式耳机啊” 这种评论总是会出现后台或者现实的朋友也会问起来&#xff0c;所以作为耳机测评的博主&#xff0c;在这里给大家科普一下到底一款好用的开放式耳机到底怎么选&#xff0c;这篇文章我花了三天…

Centos系统内磁盘分区

Centos系统内磁盘分区 建议如果有重要数据提前做好备份 以根目录扩容50G为例&#xff1a; 1、卸载/home目录 umount /home 2、删除逻辑卷 y确认即可 lvremove /dev/mapper/centos-home 3、df -h查询一下&#xff0c;/home目录已经不见了 4、向根目录分区追加50G容量 lv…

网易云小程序资料分享

链接: https://pan.baidu.com/s/1jzP52Zq4R-nUTxN334XMJg 提取码: xhny

STM32基础篇:EXTI × 事件 × EXTI标准库

EXTI EXTI简介 EXTI&#xff1a;译作外部中断/事件控制器&#xff0c;STM32的众多片上外设之一&#xff0c;能够检测外部输入信号的边沿变化并由此产生中断。 例如&#xff0c;在检测按键时&#xff0c;按键按下时会使电平产生翻转&#xff0c;因此可以使用EXTI来读取按下时…

线上线下一体开源的Hugging Face?| 这些问题不可不看……

7月&#xff0c;2024世界人工智能大会暨人工智能全球治理高级别会议&#xff08;WAIC 2024&#xff09;在上海盛大启幕&#xff0c;以“以共商促共享&#xff0c;以善治促善智”为主题进行展览&#xff0c;OpenCSG首次亮相“CSGHub和StarShip”两大产品&#xff0c;全方位展现公…

HTML5新增的input元素类型:number、range、email、color、date等

HTML5 大幅度地增加与改良了 input 元素的种类&#xff0c;可以简单地使用这些元素来实现 HTML5 之前需要使用 JavaScript 才能实现的许多功能。 到目前为止&#xff0c;大部分浏览器都支持 input 元素的种类。对于不支持新增 input 元素的浏览器&#xff0c;input 元素被统一…

kotlin数据容器

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 容器是用于存放数据的载体。容器分为数组、集合。 Kotlin作为一门全新的语言&#xff0c;肯定还是要有自己的容…

网优学习干货:xx5G速率优化现场实战版

速率概述 无线网络仍然是5G网络能力最容易受限的环节&#xff0c;无线网络技术的应用将最终决定5G网络能力的木桶深度。移动通信中传统关键技术在5G将会继续使用。5G NR在继承了LTE原有部分技术基础上&#xff0c;采用了一些技术演进和新技术创新。比如NR继承了LTE的OFDM和SC-…

ArduPilot开源飞控之AP_Mount_Topotek

ArduPilot开源飞控之AP_Mount_Topotek 1. 源由2. 框架设计3. 重要函数3.1 动态过程3.1.1 AP_Mount_Topotek::update3.1.2 AP_Mount_Backend::calculate_poi 3.2 基础能力3.2.1 AP_Mount_Topotek::healthy3.2.2 AP_Mount_Topotek::has_pan_control 3.3 设备功能3.3.1 AP_Mount_T…

python 实验八 数据分析与展示

一、实验目的 掌握掌握matplotlib库中pyplot模块的使用。 二、实验环境 Window10&#xff08;x64&#xff09;&#xff0c;Python 3.8&#xff08;x64&#xff09;&#xff0c;PyCharm Community Edition 2020.3.2&#xff08;x64&#xff09; 三、实验内容 现有列表hight…

初学SpringMVC之过滤器解决乱码

写个 login.jsp 页面 提交的 method 一般为 post&#xff08;写 get 不安全&#xff0c;地址栏上会显示&#xff09; action 表示提交后跳转的地址 &#xff08;不直接写控制器里的路径是因为配置 Tomcat 时设置了前缀路径&#xff0c;默认走 http://localhost:8080&#xf…

市面上的护眼台灯哪个牌子最好?分享学生护眼台灯十大排名

家长们对孩子的用眼健康很重视&#xff0c;为什么&#xff1f;现在是科技电子时代&#xff0c;人们对电子屏幕的依赖性高&#xff0c;小孩子年纪小&#xff0c;眼部还处于正在发育的阶段&#xff0c;他们在学校中长时间的学习读写&#xff0c;用眼时间长。而且随着科技渗入教学…

如何选择小型超声波清洗机? 2024年值得买的四款眼镜清洗机总结

久了不擦洗的眼镜&#xff0c;往往会滋生很多细菌病毒&#xff0c;久而久之就会影响到视力和眼睛健康。而超声波清洗机作为一款高效清洁物品&#xff0c;可以帮助人们快速且深度地清洁眼镜&#xff0c;很多清洗机使用久一点清洁力就减弱了&#xff0c;所以要找一款性价比高的清…

【Java EE】统一功能返回

一、拦截器 1.1 拦截器的作用 在对于数据库进行增删查改的时候&#xff0c;如果当前页面不检查用户是否登录&#xff0c;然后就能操作成功是不合理的&#xff0c;解决方法有两个&#xff1a; 对于已经写好的每个接口都加上一个判断&#xff0c;从Session中获取用户信息&…

CSS 中的 ::before 和 ::after 伪元素

目录 一、CSS 伪元素 二、::before ::after 介绍 1、::before 2、::after 3、content 常用属性值 三、::before ::after 应用场景 1、设置统一字符 2、通过背景添加图片 3、添加装饰线 4、右侧展开箭头 5、对话框小三角 6、插入icon图标 一、CSS 伪元素 CSS伪元…

Spring Boot:连接MySQL错误Public Key Retrieval is not allowed

环境&#xff1a; MySQL版本&#xff1a;8.0.17 SpringBoot版本&#xff1a;2.5.15 解决 解决方式很简单&#xff0c;在数据库配置连接字符串spring.datasource.url末尾添加&allowPublicKeyRetrievaltrue即可&#xff0c;如下图&#xff1a; 重新启动&#xff0c;恢复正常…

django招聘数据分析与可视化管理系统-计算机毕业设计源码55218

摘要 随着互联网的迅速发展&#xff0c;招聘数据在规模和复杂性上呈现爆炸式增长&#xff0c;对数据的深入分析和有效可视化成为招聘决策和招聘管理的重要手段。本论文旨在构建一个基于Python的招聘数据分析与可视化管理系统。 该平台以主流招聘平台为数据源&#xff0c;利用Py…

四元数和旋转矩阵的求导

四元数的导数 四元数关于时间求导的推导 本质&#xff1a; 求导的定义是函数值的微增量关于自变量的微增量的极限。表示旋转的单位四元数作差后&#xff0c;其不再是单位四元数&#xff0c;也就不是旋转四元数了。单位四元数作差后&#xff0c;得到是被减四元数所在空间的切空…

直观易用的大模型开发框架LangChain,你会了没?

目录 简介基本组件小试牛刀关于沟通代码案例&#xff1a;调用Embedding、Completion、Chat Model总结 目前LangChain框架在集团大模型接入手册中的学习案例有限&#xff0c;为了让大家可以快速系统地了解LangChain大模型框架并开发&#xff0c;产出此文章。本文章包含了LangCha…