
安全能力集成:鸿蒙 TEE 环境在 RN 应用的加密实践(附代码)
鸿蒙的 TEE(Trusted Execution Environment,可信执行环境) 是基于硬件隔离的安全空间(如ARM的Secure Enclave),专为保护敏感数据(如密钥、用户隐私)而生。在 React Native(RN)应用中集成鸿蒙 TEE,可解决传统加密方案的痛点(如密钥易被提取、数据传输易被截获),实现「端到端安全」。本文结合鸿蒙 TEE 特性与 RN 开发流程,总结一套 敏感数据加密存储+传输签名 的完整实践方案,代码可直接复用。
一、为什么选择鸿蒙 TEE?
传统加密方案(如Android Keystore、iOS Keychain)依赖操作系统保护,存在被Root/越狱的风险。鸿蒙 TEE 的核心优势:
硬件级隔离:敏感操作在独立的安全芯片中执行,操作系统无法访问密钥或计算过程;
跨设备一致性:鸿蒙全场景设备(手机、平板、车机)统一 TEE 接口,降低适配成本;
与 RN 深度兼容:通过原生模块封装,无缝集成到 RN 应用中。
二、前置准备(2分钟)
开发环境:DevEco Studio 5.0+(https://developer.harmonyos.com/cn/develop/deveco-studio/)。
设备要求:支持鸿蒙 TEE 的设备(如HUAWEI Mate 60系列、鸿蒙智联平板)。
权限配置:在 module.json5 中声明 TEE 相关权限(如 ohos.permission.SECURE_STORAGE)。
三、核心场景1:敏感数据加密存储(用户密码/Token)
用户密码、登录 Token 等敏感数据若明文存储,可能被恶意应用窃取。通过鸿蒙 TEE 加密存储,可实现「密钥不落地」的安全方案。
原生层:封装 TEE 加密接口(Java)
鸿蒙 TEE 提供 @ohos.security.secureElement 模块,用于安全存储和加密运算。我们通过 Java 原生模块封装这些接口,供 RN 调用。
// 原生模块:SecureTEEModule.java(路径:entry/src/main/java/com/example/rnapp/SecureTEEModule.java)
package com.example.rnapp;
import ohos.aafwk.content.Operation;
import ohos.aafwk.content.Intent;
import ohos.app.Context;
import ohos.security.secureElement.SecureElement;
import ohos.security.secureElement.SecureElementException;
import ohos.utils.net.Uri;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.Promise;
import java.util.HashMap;
import java.util.Map;
public class SecureTEEModule extends ReactContextBaseJavaModule {
private static final String MODULE_NAME = “SecureTEE”;
private SecureElement secureElement;
public SecureTEEModule(ReactApplicationContext reactContext) {
super(reactContext);
// 初始化 TEE 安全元素(需设备支持)
try {
secureElement = SecureElement.getSecureElement();
catch (SecureElementException e) {
e.printStackTrace();
}
@Override
public String getName() {
return MODULE_NAME;
// 原生方法:加密数据并存储到 TEE
// 参数:plainText(明文)、keyAlias(密钥别名)
// 返回:加密后的数据(Base64编码)
public void encryptAndStore(String plainText, String keyAlias, Promise promise) {
try {
// 1. 生成或获取密钥(首次调用时生成)
if (!secureElement.containsKey(keyAlias)) {
secureElement.generateKey(keyAlias, "AES/GCM/NoPadding");
// 2. 加密数据
byte[] encryptedData = secureElement.encrypt(keyAlias, plainText.getBytes());
// 3. 存储到 TEE 安全存储(可选,TEE 内部已加密)
secureElement.saveData(keyAlias + "_data", encryptedData);
// 返回 Base64 编码结果
promise.resolve(android.util.Base64.encodeToString(encryptedData, android.util.Base64.DEFAULT));
catch (SecureElementException e) {
promise.reject("encrypt_error", e.getMessage());
}
// 原生方法:从 TEE 解密数据
// 参数:encryptedText(Base64加密数据)、keyAlias(密钥别名)
// 返回:明文
public void decryptFromStore(String encryptedText, String keyAlias, Promise promise) {
try {
// 1. 从 TEE 读取加密数据
byte[] encryptedData = secureElement.loadData(keyAlias + "_data");
// 2. 解密数据
byte[] decryptedData = secureElement.decrypt(keyAlias, encryptedData);
promise.resolve(new String(decryptedData));
catch (SecureElementException e) {
promise.reject("decrypt_error", e.getMessage());
}
RN 层:调用 TEE 加密接口(TypeScript)
在 RN 中通过 NativeModules 调用原生模块,实现敏感数据的加密存储与解密读取。
// RN 组件:SecureStorage.tsx
import React from ‘react’;
import { View, Text, Button, StyleSheet } from ‘react-native’;
// 访问鸿蒙原生模块(需确保模块已正确注册)
const { SecureTEE } = require(‘react-native’).NativeModules;
const SecureStorage = () => {
const [encryptedText, setEncryptedText] = React.useState(‘’);
const [plainText, setPlainText] = React.useState(‘’);
// 加密并存储
const handleEncrypt = async () => {
try {
const result = await SecureTEE.encryptAndStore(plainText, ‘user_token’);
setEncryptedText(result);
catch (error) {
alert(加密失败:${error.message});
};
// 解密并显示
const handleDecrypt = async () => {
try {
const result = await SecureTEE.decryptFromStore(encryptedText, ‘user_token’);
setPlainText(result);
catch (error) {
alert(解密失败:${error.message});
};
return (
<View style={styles.container}>
<Text style={styles.title}>鸿蒙 TEE 敏感数据加密存储</Text>
<Text>输入明文:</Text>
<TextInput
style={styles.input}
value={plainText}
onChangeText={setPlainText}
placeholder=“输入密码或Token”
/>
<Button title=“加密存储” onPress={handleEncrypt} />
{encryptedText && (
<>
<Text>加密结果(Base64):</Text>
<Text selectable>{encryptedText}</Text>
</>
)}
<Button title=“解密显示” onPress={handleDecrypt} />
{plainText && (
<>
<Text>解密结果:</Text>
<Text selectable>{plainText}</Text>
</>
)}
</View>
);
};
const styles = StyleSheet.create({
container: { flex: 1, padding: 20 },
title: { fontSize: 20, fontWeight: ‘bold’, marginBottom: 20 },
input: { height: 40, borderWidth: 1, padding: 10, marginBottom: 10 }
});
export default SecureStorage;
注册原生模块(关键配置)
在 entry/src/main/resources/base/profile/module.json5 中声明原生模块,确保 RN 能正确调用:
“module”: {
// ...其他配置
"abilities": [
“name”: “.EntryAbility”,
"srcEntry": "./ets/pages/EntryAbility.ts",
"skills": [
// 声明支持安全存储技能
“entities”: [“entity.system.secure_storage”],
"actions": ["action.system.secure_encrypt"]
]
],
"requestPermissions": [
“name”: “ohos.permission.SECURE_STORAGE” // 申请 TEE 存储权限
]
}
四、核心场景2:传输签名验证(防篡改)
在 RN 应用与服务器通信时,使用 TEE 生成的私钥对请求参数签名,服务器用公钥验签,防止数据被篡改或伪造。
原生层:生成密钥对并签名(Java)
// 扩展 SecureTEEModule.java,添加签名功能
public void generateKeyPair(String keyAlias, Promise promise) {
try {
// 生成 RSA 密钥对(TEE 内部存储私钥,公钥导出)
secureElement.generateRsaKeyPair(keyAlias, 2048);
// 获取公钥(Base64编码)
byte[] publicKeyBytes = secureElement.getPublicKey(keyAlias);
String publicKey = android.util.Base64.encodeToString(publicKeyBytes, android.util.Base64.DEFAULT);
promise.resolve(publicKey);
catch (SecureElementException e) {
promise.reject("keypair_error", e.getMessage());
}
public void signData(String plainText, String keyAlias, Promise promise) {
try {
// 从 TEE 获取私钥(不可导出,仅在安全环境中使用)
byte[] privateKeyBytes = secureElement.getPrivateKey(keyAlias);
// 使用私钥签名(RSA/SHA256)
Signature signature = Signature.getInstance(“SHA256withRSA”);
PrivateKey privateKey = KeyFactory.getInstance(“RSA”).generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));
signature.initSign(privateKey);
signature.update(plainText.getBytes());
byte[] signedData = signature.sign();
// 返回 Base64 编码的签名
promise.resolve(android.util.Base64.encodeToString(signedData, android.util.Base64.DEFAULT));
catch (Exception e) {
promise.reject("sign_error", e.getMessage());
}
RN 层:实现签名验证流程(TypeScript)
// 扩展 SecureStorage.tsx,添加签名功能
const handleGenerateKeyPair = async () => {
try {
const publicKey = await SecureTEE.generateKeyPair(‘app_sign_key’);
setPublicKey(publicKey);
catch (error) {
alert(生成密钥失败:${error.message});
};
const handleSignRequest = async () => {
try {
const signedData = await SecureTEE.signData(plainText, ‘app_sign_key’);
setSignedData(signedData);
// 将 signedData 和 plainText 发送到服务器验签
await sendToServer({ plainText, signedData });
catch (error) {
alert(签名失败:${error.message});
};
五、安全增强最佳实践
最小化密钥暴露:私钥仅在 TEE 内部使用,禁止导出到 RN 层或 JS 环境。
防重放:在签名中加入时间戳或随机数(Nonce),服务器验证时检查时效性。
设备可信检测:通过 @ohos.security.deviceAuth 模块检测设备是否 Root/越狱,若不可信则禁用敏感操作。
日志脱敏:避免在日志中打印密钥、签名等敏感信息,防止通过日志泄露。
六、实测效果与总结
通过鸿蒙 TEE 集成,RN 应用的敏感数据处理能力显著提升:
密钥安全性:私钥终身存储于 TEE 安全芯片,无法通过常规手段提取;
数据防篡改:传输签名结合 TEE 硬件隔离,确保请求参数未被恶意修改;
跨设备兼容:鸿蒙全场景设备统一 TEE 接口,无需为不同设备重复开发。
关键总结
鸿蒙 TEE 与 RN 的集成,为敏感数据处理提供了「硬件级安全」的解决方案。核心步骤是:
原生层封装 TEE 接口(加密/解密、签名/验签);
RN 层通过桥接调用原生接口,实现业务逻辑;
结合设备可信检测、日志脱敏等策略,构建完整安全体系。
掌握这些实践后,你的 RN 应用将具备抵御大部分恶意的能力,用户数据安全更有保障! 🔒
