【HarmonyOS 5】鴻蒙TEE(可信執行環境)詳解
一、TEE是什么?
1、TEE的定義:
可信執行環境(Trusted Execution Environment),簡稱TEE,是存在于智能手機、平板或任意移動設備主處理器中的一個安全區域,確保各種敏感數據在一個可信環境中被存儲、處理和受到保護。
2、TEE的作用
簡單來說,TEE構建一個隔離的安全執行環境。該環境具備獨立的計算和存儲能力,能確保在其中運行的程序和數據受到嚴格保護,即使主系統被GJ或篡改,TEE內的內容也能保持安全。
TEE為授權安全軟件,也稱為“可信應用”提供一個安全的執行環境,通過實施保護、保密性、完整性和數據訪問權限確保端到端的安全。
3、TEE的能力歸屬:
TEE在鴻蒙系統中以Kit的形式,提供給App使用。在Device Security Kit中包括應用設備狀態檢測、安全檢測、可信應用服務、業務風險檢測能力。
4、硬件級安全保障
依賴芯片級的安全能力(如ARM的TrustZone、Intel的SGX等技術),通過硬件隔離機制確保TEE的安全性,降低軟件層面被GJ的風險。
5、 與鴻蒙系統深度集成
適配鴻蒙的微內核架構和分布式特性,可在多設備(如手機、智能手表、智能家居設備)之間實現安全能力的協同,例如在分布式場景下統一管理用戶身份和數據安全。
6、動態信任鏈機制
從系統啟動階段就建立可信根,通過信任鏈傳遞確保TEE環境的完整性,防止啟動過程中被惡意篡改。
7、 移動支付與金融安全
在進行掃碼支付、銀行卡信息輸入等操作時,鴻蒙TEE可保護支付密鑰和交易數據,防止被惡意軟件竊取,類似傳統手機中TEE用于保護銀聯閃付等功能。
8、生物特征識別
存儲和處理指紋、人臉等生物特征數據,確保解鎖、支付等場景中生物信息的安全,例如手機解鎖時,生物特征的比對過程在TEE中完成。
9、 數字版權管理(DRM)
保護視頻、音樂等數字內容的版權,確保只有授權設備和用戶才能播放加密的媒體文件,防止盜版內容傳播。
10、 企業級安全應用
為企業提供安全的身份認證、數據加密傳輸等功能,例如在鴻蒙平板或筆記本中,TEE可保護企業機密文件和遠程辦公的安全連接。
二、如何使用TEE?
目前提供可信應用服務,例如:安全攝像頭場景,安全地址位置場景,安全圖像壓縮和裁剪場景。
【從API12開始,開發者需要開通可信應用服務才可以正常使用接口,否則調用接口會拋出異常,已上架的應用需要開通服務后重新上架。】
1、首先我們需要給App開通可信應用服務:
默認在AGC平臺是沒有該設置入門。需要App通過白名單審核,審核通過后方可開通可信應用服務。
說明。
開通“可信應用服務”需要先申請進入允許清單,請將Developer ID、公司名稱、應用名稱、申請使用的服務和使用該服務的場景,發送到agconnect@huawei.com。AGC運營將審核相關材料,通過后將為您配置受限開放服務使用的名單,審核周期為1-3個工作日,請耐心等待。
可信應用服務:點擊“可信應用服務”右側的按鈕,接入“可信應用服務”:
2、可信服務調用流程:
我們以為安全相機為例講解:
import { camera } from '@kit.CameraKit';
import { image } from '@kit.ImageKit';@Entry
@Component
struct SecureCameraDemo {private cameraManager: camera.CameraManager = camera.getCameraManager();private secureCamera: camera.CameraDevice | null = null;private cameraInput: camera.CameraInput | null = null;private previewOutput: camera.PreviewOutput | null = null;private secureOutput: camera.PreviewOutput | null = null;private secureSession: camera.SecureSession | null = null;private imageReceiver: image.ImageReceiver | null = null;private previewProfile: camera.Profile | null = null;private secureCameraSerialNumber: bigint | null = null;private previewSurfaceId: string = '';aboutToAppear() {this.initSecureCamera();}aboutToDisappear() {this.releaseResources();}// 初始化安全相機async initSecureCamera() {try {// 選擇支持安全相機的設備await this.selectSecureCameraDevice();if (!this.secureCamera) {console.error('未找到支持安全相機的設備');return;}// 查詢相機設備在安全模式下支持的輸出能力await this.getSecureCameraOutputCapability();if (!this.previewProfile) {console.error('未獲取到支持的預覽配置');return;}// 創建設備輸入輸出await this.createInputAndOutputs();// 打開安全設備await this.openSecureCamera();// 創建安全相機會話,配流啟流await this.openSecureSession();// 注冊安全數據流回調this.registerSecureDataCallback();} catch (error) {console.error(`初始化安全相機失敗: ${JSON.stringify(error)}`);}}// 選擇支持安全相機的設備async selectSecureCameraDevice() {const cameraArray = await this.cameraManager.getSupportedCameras();for (const cameraDevice of cameraArray) {if (await this.isSecureCamera(cameraDevice)) {this.secureCamera = cameraDevice;console.info('找到支持安全相機的設備');break;}}}// 判斷設備是否支持安全相機async isSecureCamera(cameraDevice: camera.CameraDevice): Promise<boolean> {const sceneModes = await this.cameraManager.getSupportedSceneModes(cameraDevice);const secureMode = sceneModes.find(mode => mode === camera.SceneMode.SECURE_PHOTO);return secureMode !== undefined;}// 查詢相機設備在安全模式下支持的輸出能力async getSecureCameraOutputCapability() {if (!this.secureCamera) return;const outputCap = await this.cameraManager.getSupportedOutputCapability(this.secureCamera, camera.SceneMode.SECURE_PHOTO);// 選擇推薦的預覽分辨率 640*480this.previewProfile = outputCap.previewProfiles.find(profile => profile.size.width === 640 && profile.size.height === 480);// 如果沒有找到 640*480 的分辨率,選擇第一個可用的if (!this.previewProfile && outputCap.previewProfiles.length > 0) {this.previewProfile = outputCap.previewProfiles[0];}}// 創建設備輸入輸出async createInputAndOutputs() {if (!this.secureCamera || !this.previewProfile) return;// 創建輸入流this.cameraInput = await this.cameraManager.createCameraInput(this.secureCamera);// 創建普通預覽輸出流this.previewSurfaceId = this.createPreviewSurface();this.previewOutput = await this.cameraManager.createPreviewOutput(this.previewProfile, this.previewSurfaceId);// 創建安全數據輸出流this.imageReceiver = image.createImageReceiver({ width: this.previewProfile.size.width, height: this.previewProfile.size.height },image.ImageFormat.JPEG, 8);const secureSurfaceId = await this.imageReceiver.getReceivingSurfaceId();this.secureOutput = await this.cameraManager.createPreviewOutput(this.previewProfile, secureSurfaceId);}// 創建預覽SurfacecreatePreviewSurface(): string {// 這里需要實現創建預覽Surface的邏輯// 實際開發中可能需要使用鴻蒙的UI組件來創建預覽Surfacereturn 'previewSurfaceId';}// 打開安全設備async openSecureCamera() {if (!this.cameraInput) return;// 打開安全相機并獲取序列號this.secureCameraSerialNumber = await this.cameraInput.open(true);console.info(`安全相機已打開,序列號: ${this.secureCameraSerialNumber}`);// 使用序列號創建證明密鑰和初始化證明會話// 注意:這部分需要調用DeviceSecurity Kit的API,此處僅為示例this.initializeAttestationSession(this.secureCameraSerialNumber);}// 初始化證明會話(調用DeviceSecurity Kit)initializeAttestationSession(serialNumber: bigint) {// 實際開發中需要調用DeviceSecurity Kit的API// 以下為示例代碼,需要根據實際API進行調整console.info(`使用安全相機序列號 ${serialNumber} 初始化證明會話`);// const deviceSecurityKit = ...; // 獲取DeviceSecurity Kit實例// deviceSecurityKit.createAttestationKey(serialNumber);// deviceSecurityKit.initializeAttestationSession(...);}// 創建安全相機會話,配流啟流async openSecureSession() {if (!this.cameraManager || !this.cameraInput || !this.previewOutput || !this.secureOutput) return;try {this.secureSession = await this.cameraManager.createSession(camera.SceneMode.SECURE_PHOTO);if (!this.secureSession) {console.error('創建安全會話失敗');return;}await this.secureSession.beginConfig();await this.secureSession.addInput(this.cameraInput);await this.secureSession.addOutput(this.previewOutput);await this.secureSession.addOutput(this.secureOutput);await this.secureSession.addSecureOutput(this.secureOutput); // 標記為安全輸出await this.secureSession.commitConfig();await this.secureSession.start();console.info('安全會話已啟動');} catch (error) {console.error(`打開安全會話失敗: ${JSON.stringify(error)}`);}}// 注冊安全數據流回調registerSecureDataCallback() {if (!this.imageReceiver) return;this.imageReceiver.on('imageArrival', async () => {try {const img = await this.imageReceiver!.readNextImage();const component = await img.getComponent(image.ComponentType.JPEG);const buffer = component.byteBuffer;// 將安全數據發送到服務器進行驗證this.sendSecureDataToServer(buffer);// 處理完后釋放圖像資源img.release();} catch (error) {console.error(`處理安全數據失敗: ${JSON.stringify(error)}`);}});}// 將安全數據發送到服務器進行驗證sendSecureDataToServer(buffer: ArrayBuffer) {// 實際開發中需要實現將安全數據發送到服務器的邏輯console.info(`發送安全數據到服務器,數據大小: ${buffer.byteLength} 字節`);// 示例:使用fetch API發送數據/*fetch('https://your-server.com/verify-secure-data', {method: 'POST',body: buffer,headers: {'Content-Type': 'application/octet-stream','Secure-Camera-Serial': this.secureCameraSerialNumber?.toString() || ''}}).then(response => response.json()).then(result => {console.info('服務器驗證結果:', result);}).catch(error => {console.error('發送安全數據失敗:', error);});*/}// 釋放資源async releaseResources() {try {// 停止會話if (this.secureSession) {await this.secureSession.stop();await this.secureSession.release();this.secureSession = null;}// 釋放輸出if (this.previewOutput) {await this.previewOutput.release();this.previewOutput = null;}if (this.secureOutput) {await this.secureOutput.release();this.secureOutput = null;}// 釋放輸入if (this.cameraInput) {await this.cameraInput.release();this.cameraInput = null;}// 釋放圖像接收器if (this.imageReceiver) {this.imageReceiver.release();this.imageReceiver = null;}console.info('安全相機資源已釋放');} catch (error) {console.error(`釋放資源失敗: ${JSON.stringify(error)}`);}}build() {Column() {Text('安全相機演示').fontSize(20).fontWeight(FontWeight.Bold).margin({ top: 20, bottom: 20 })// 這里可以添加預覽界面組件// 實際開發中需要根據鴻蒙的UI組件來實現預覽顯示Text('安全相機預覽區域').width('100%').height(300).backgroundColor('#CCCCCC').textAlign(TextAlign.Center).margin({ bottom: 20 })Button('釋放相機').onClick(() => {this.releaseResources();})}.width('100%').height('100%').padding(15)}
}
三、環境隔離的使用方法
綜上所述,基于TEE的環境。我們將敏感信息加密后,放在TEE環境中,就可以做到最高的安全保護。
對用戶的敏感數據(如生物特征信息、支付密碼、加密密鑰等)進行加密存儲和處理,防止數據被未授權的程序或進程訪問。
1. 使用DeviceSecurity Kit訪問TEE
HarmonyOS提供了DeviceSecurity Kit
來訪問TEE功能,包括創建安全密鑰、執行安全操作和存儲敏感數據。主要步驟如下:
步驟1:導入依賴
import { deviceSecurity } from '@ohos.security.deviceSecurity';
步驟2:獲取TEE會話
async function getTEESession() {try {// 獲取TEE服務實例const teeService = await deviceSecurity.getTrustedExecutionEnvironmentService();// 創建安全會話(根據實際需求選擇合適的安全級別)const session = await teeService.createSession({authType: deviceSecurity.AuthType.ALL, // 認證類型authLevel: deviceSecurity.AuthLevel.SYSTEM, // 認證級別userId: 0 // 用戶ID});return session;} catch (error) {console.error(`獲取TEE會話失敗: ${JSON.stringify(error)}`);return null;}
}
2. 在TEE中緩存數據
在TEE環境中緩存數據有兩種主要方式:安全存儲和安全內存。
方式1:安全存儲(持久化緩存)
使用TrustedStorage
接口將數據加密存儲在TEE中:
async function cacheDataSecurely(session: deviceSecurity.TrustedExecutionEnvironmentSession, key: string, data: string) {try {// 將數據轉換為ArrayBufferconst dataBuffer = new TextEncoder().encode(data);// 創建安全存儲對象const trustedStorage = await session.getTrustedStorage();// 存儲數據(自動加密)await trustedStorage.save(key, dataBuffer);console.info(`數據已安全存儲,鍵: ${key}`);} catch (error) {console.error(`安全存儲失敗: ${JSON.stringify(error)}`);}
}
方式2:安全內存(臨時緩存)
使用TrustedMemory
接口在TEE的安全內存中臨時緩存數據:
async function cacheDataInSecureMemory(session: deviceSecurity.TrustedExecutionEnvironmentSession, data: string) {try {// 將數據轉換為ArrayBufferconst dataBuffer = new TextEncoder().encode(data);// 創建安全內存區域const trustedMemory = await session.allocateTrustedMemory(dataBuffer.byteLength);// 寫入數據到安全內存await trustedMemory.write(dataBuffer);console.info('數據已緩存到安全內存');return trustedMemory;} catch (error) {console.error(`安全內存緩存失敗: ${JSON.stringify(error)}`);return null;}
}
3. 從TEE中讀取緩存數據
根據存儲方式的不同,讀取數據的方法也不同:
讀取安全存儲數據
async function readSecurelyStoredData(session: deviceSecurity.TrustedExecutionEnvironmentSession, key: string) {try {const trustedStorage = await session.getTrustedStorage();const dataBuffer = await trustedStorage.read(key);// 將ArrayBuffer轉換為字符串const data = new TextDecoder().decode(dataBuffer);return data;} catch (error) {console.error(`讀取安全存儲數據失敗: ${JSON.stringify(error)}`);return null;}
}
讀取安全內存數據
async function readDataFromSecureMemory(trustedMemory: deviceSecurity.TrustedMemory) {try {const dataBuffer = await trustedMemory.read();const data = new TextDecoder().decode(dataBuffer);return data;} catch (error) {console.error(`讀取安全內存數據失敗: ${JSON.stringify(error)}`);return null;}
}
4. 釋放資源
使用完畢后,需要釋放TEE資源以確保安全性:
async function releaseTEEResources(session: deviceSecurity.TrustedExecutionEnvironmentSession, trustedMemory?: deviceSecurity.TrustedMemory) {try {// 釋放安全內存(如果有)if (trustedMemory) {await trustedMemory.release();}// 關閉會話await session.close();console.info('TEE資源已釋放');} catch (error) {console.error(`釋放TEE資源失敗: ${JSON.stringify(error)}`);}
}
完整示例
下面是一個完整的示例,演示如何在TEE中緩存和讀取數據:
import { deviceSecurity } from '@ohos.security.deviceSecurity';async function demoTEECaching() {// 1. 獲取TEE會話const session = await getTEESession();if (!session) return;try {// 2. 緩存數據到安全存儲await cacheDataSecurely(session, 'sensitiveKey', '這是敏感數據');// 3. 從安全存儲讀取數據const storedData = await readSecurelyStoredData(session, 'sensitiveKey');console.info(`從安全存儲讀取的數據: ${storedData}`);// 4. 緩存數據到安全內存const secureMemory = await cacheDataInSecureMemory(session, '臨時敏感數據');// 5. 從安全內存讀取數據if (secureMemory) {const memoryData = await readDataFromSecureMemory(secureMemory);console.info(`從安全內存讀取的數據: ${memoryData}`);}} catch (error) {console.error(`TEE數據緩存演示失敗: ${JSON.stringify(error)}`);} finally {// 6. 釋放資源await releaseTEEResources(session);}
}
注意事項
-
權限要求:使用TEE功能需要在
config.json
中聲明相應權限:{"requestPermissions": [{"name": "ohos.permission.USE_TRUSTED_ENVIRONMENT","reason": "需要訪問TEE環境"}] }
-
數據大小限制:TEE的安全內存通常有限,不要存儲過大的數據。
-
生命周期管理:確保在不需要時及時釋放TEE資源,避免內存泄漏。
-
錯誤處理:TEE操作可能因硬件限制或安全策略失敗,需要完善的錯誤處理。
-
兼容性:不同設備的TEE實現可能存在差異,建議進行充分測試。