一文带你了解HarmonyOS开发中的安全区域是什么
📌 核心要点:HUKS 是 HarmonyOS 安全体系的根基,密钥在 TEE 中生成和运算,永远不会以明文形式暴露给普通世界
一、背景与动机
你有没有想过——手机里存着你的银行卡号、支付密码、指纹数据、聊天记录,这些最敏感的信息,为什么不怕被黑客窃取?答案就是安全区域。
安全区域就像银行的金库。普通世界(Rich Execution Environment, REE)是银行的大堂,所有人都能进出;安全区域(Trusted Execution Environment, TEE)是金库,只有经过授权的操作才能进入,而且金库里的东西永远不能被带出来。
HarmonyOS 的 HUKS(Universal KeyStore)就是连接普通世界和安全区域的桥梁。它让你的应用可以在 TEE 中生成密钥、存储密钥、使用密钥进行加密解密,而密钥本身永远不会离开 TEE。即使手机被 root、应用被反编译,攻击者也拿不到你的密钥。
这不是什么可选的高级功能——如果你的应用处理支付、身份认证、医疗数据等敏感信息,HUKS 就是你必须掌握的安全基石。
二、核心原理
2.1 TEE 安全架构

flowchart TB
subgraph REE["普通世界(REE)"]
A[应用进程] --> B[HUKS API]
B --> C[HUKS Service]
end
subgraph TEE["安全世界(TEE)"]
D[TEE OS<br/>Trusted OS]
E[密钥存储区<br/>Secure Storage]
F[加密引擎<br/>Crypto Engine]
G[安全应用<br/>Trusted App]
end
C <-->|安全通道<br/>SMC调用| D
D --> E
D --> F
D --> G
subgraph Hardware["硬件安全"]
H[TrustZone<br/>ARM TZ]
I[安全存储<br/>eFuse/RPMB]
J[硬件加密引擎]
end
D --- H
E --- I
F --- J
classDef primary fill:#4CAF50,stroke:#388E3C,color:#fff
classDef warning fill:#FF9800,stroke:#F57C00,color:#fff
classDef error fill:#F44336,stroke:#D32F2F,color:#fff
classDef info fill:#2196F3,stroke:#1976D2,color:#fff
classDef purple fill:#9C27B0,stroke:#7B1FA2,color:#fff
class A,B,C info
class D,E,F,G primary
class H,I,J error
2.2 HUKS 核心安全原则
HUKS 遵循三个核心安全原则:
- 密钥永不外泄:密钥在 TEE 中生成,加密运算在 TEE 中完成,密钥明文永远不会出现在 REE 中
- 访问控制严格:密钥可以绑定用户认证(指纹/PIN),只有通过认证才能使用密钥
- 安全存储可靠:密钥材料存储在 TEE 的安全存储区(RPMB),即使物理拆机也无法提取
2.3 密钥生命周期
flowchart LR
A[密钥生成<br/>generateKey] --> B[密钥存储<br/>TEE安全存储]
B --> C[密钥使用<br/>加密/解密/签名/验签]
C --> D{是否过期?}
D -->|否| C
D -->|是| E[密钥删除<br/>deleteKey]
B --> F[密钥导出<br/>仅公钥可导出]
G[密钥导入<br/>importKey] --> B
H[密钥证明<br/>attestKey] --> I[设备证书链]
classDef primary fill:#4CAF50,stroke:#388E3C,color:#fff
classDef warning fill:#FF9800,stroke:#F57C00,color:#fff
classDef error fill:#F44336,stroke:#D32F2F,color:#fff
classDef info fill:#2196F3,stroke:#1976D2,color:#fff
classDef purple fill:#9C27B0,stroke:#7B1FA2,color:#fff
class A,G primary
class B,F info
class C purple
class E error
class H,I warning
2.4 加密算法选择指南
| 算法类型 | 推荐算法 | 密钥长度 | 适用场景 | 性能 |
|---|---|---|---|---|
| 对称加密 | AES-256-GCM | 256位 | 大量数据加密 | ⚡最快 |
| 非对称加密(签名) | ECDSA-P256 | 256位 | 身份验证、数字签名 | 🔶中等 |
| 非对称加密(加密) | RSA-2048/OAEP | 2048位 | 小数据加密、密钥交换 | 🐢较慢 |
| 密钥协商 | ECDH-P256 | 256位 | 安全通信建立 | 🔶中等 |
| 哈希 | SHA-256 | - | 数据完整性校验 | ⚡最快 |
| HMAC | HMAC-SHA256 | 256位 | 消息认证码 | ⚡最快 |
三、代码实战
3.1 密钥生成与安全存储
最基础的操作——在 TEE 中生成密钥,并使用密钥进行加密解密。
import { huks } from '@kit.UniversalKeystoreKit';
import { BusinessError } from '@kit.BasicServicesKit';
/**
* HUKS 密钥管理器
* 封装密钥的生成、存储、使用和删除操作
*/
class HuksKeyManager {
/**
* 生成AES对称加密密钥
* 密钥在TEE中生成,永远不会暴露给REE
* @param keyAlias 密钥别名(用于后续引用密钥)
*/
async generateAesKey(keyAlias: string): Promise<boolean> {
try {
// 定义密钥属性
const properties: huks.HuksParam[] = [
// 算法:AES
{ tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_AES },
// 密钥用途:加密和解密
{ tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT |
huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT },
// 密钥长度:256位
{ tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 },
// 填充模式:PKCS7
{ tag: huks.HuksTag.HUKS_TAG_PADDING, value: huks.HuksKeyPadding.HUKS_PADDING_PKCS7 },
// 分组模式:GCM(带认证的加密模式)
{ tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, value: huks.HuksCipherMode.HUKS_MODE_GCM },
// 密钥不可导出(安全要求)
{ tag: huks.HuksTag.HUKS_TAG_EXPORTABLE, value: false },
// 密钥不可删除(除非主动调用deleteKey)
{ tag: huks.HuksTag.HUKS_TAG_NO_AUTH_REQUIRED, value: true },
];
const options: huks.HuksOptions = {
properties: properties,
inData: new Uint8Array(0),
};
// 在TEE中生成密钥
await huks.generateKeyItem(keyAlias, options);
console.info(`[HuksKey] AES密钥生成成功: alias=${keyAlias}`);
return true;
} catch (error) {
const err = error as BusinessError;
console.error(`[HuksKey] 生成AES密钥失败: code=${err.code}, msg=${err.message}`);
return false;
}
}
/**
* 生成ECDSA非对称签名密钥对
* 公钥可导出,私钥永不离开TEE
* @param keyAlias 密钥别名
*/
async generateEcdsaKeyPair(keyAlias: string): Promise<boolean> {
try {
const properties: huks.HuksParam[] = [
// 算法:ECDSA
{ tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_ECC },
// 密钥用途:签名和验签
{ tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_SIGN |
huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_VERIFY },
// 密钥长度:256位(P-256曲线)
{ tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_ECC_KEY_SIZE_256 },
// 摘要算法:SHA256
{ tag: huks.HuksTag.HUKS_TAG_DIGEST, value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256 },
// 私钥不可导出
{ tag: huks.HuksTag.HUKS_TAG_EXPORTABLE, value: false },
];
const options: huks.HuksOptions = {
properties: properties,
inData: new Uint8Array(0),
};
await huks.generateKeyItem(keyAlias, options);
console.info(`[HuksKey] ECDSA密钥对生成成功: alias=${keyAlias}`);
return true;
} catch (error) {
const err = error as BusinessError;
console.error(`[HuksKey] 生成ECDSA密钥对失败: ${err.message}`);
return false;
}
}
/**
* 使用AES密钥加密数据
* @param keyAlias 密钥别名
* @param plainData 明文数据
*/
async encryptData(keyAlias: string, plainData: Uint8Array): Promise<EncryptedData | null> {
try {
// 第一步:初始化加密操作,获取IV等参数
const initProperties: huks.HuksParam[] = [
{ tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_AES },
{ tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT },
{ tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 },
{ tag: huks.HuksTag.HUKS_TAG_PADDING, value: huks.HuksKeyPadding.HUKS_PADDING_PKCS7 },
{ tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, value: huks.HuksCipherMode.HUKS_MODE_GCM },
];
const initOptions: huks.HuksOptions = {
properties: initProperties,
inData: new Uint8Array(0),
};
// 初始化加密会话
const handle = await huks.initSession(keyAlias, initOptions);
console.info(`[HuksEncrypt] 加密会话已初始化: handle=${handle.handle}`);
// 第二步:分段加密数据(支持大数据量)
const updateOptions: huks.HuksOptions = {
properties: initProperties,
inData: plainData,
};
const updateResult = await huks.updateSession(handle.handle, updateOptions);
// 第三步:完成加密,获取认证标签(GCM模式的AEAD标签)
const finishOptions: huks.HuksOptions = {
properties: initProperties,
inData: new Uint8Array(0),
};
const finishResult = await huks.finishSession(handle.handle, finishOptions);
// 合并加密结果
const encryptedData: EncryptedData = {
ciphertext: new Uint8Array([
...this.uInt8ArrayToArray(updateResult.outData),
...this.uInt8ArrayToArray(finishResult.outData),
]),
// GCM模式需要保存Nonce和AEAD标签用于解密
nonce: this.extractNonce(initProperties),
aeadTag: finishResult.outData,
};
console.info(`[HuksEncrypt] 数据加密成功,密文长度: ${encryptedData.ciphertext.length}`);
return encryptedData;
} catch (error) {
const err = error as BusinessError;
console.error(`[HuksEncrypt] 加密失败: code=${err.code}, msg=${err.message}`);
return null;
}
}
/**
* 使用AES密钥解密数据
* @param keyAlias 密钥别名
* @param encryptedData 加密数据
*/
async decryptData(keyAlias: string, encryptedData: EncryptedData): Promise<Uint8Array | null> {
try {
const properties: huks.HuksParam[] = [
{ tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_AES },
{ tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT },
{ tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 },
{ tag: huks.HuksTag.HUKS_TAG_PADDING, value: huks.HuksKeyPadding.HUKS_PADDING_PKCS7 },
{ tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, value: huks.HuksCipherMode.HUKS_MODE_GCM },
];
const initOptions: huks.HuksOptions = {
properties: properties,
inData: new Uint8Array(0),
};
const handle = await huks.initSession(keyAlias, initOptions);
// 更新密文数据
const updateOptions: huks.HuksOptions = {
properties: properties,
inData: encryptedData.ciphertext,
};
const updateResult = await huks.updateSession(handle.handle, updateOptions);
// 完成解密
const finishOptions: huks.HuksOptions = {
properties: properties,
inData: encryptedData.aeadTag ?? new Uint8Array(0),
};
const finishResult = await huks.finishSession(handle.handle, finishOptions);
// 合并解密结果
const plainData = new Uint8Array([
...this.uInt8ArrayToArray(updateResult.outData),
...this.uInt8ArrayToArray(finishResult.outData),
]);
console.info(`[HuksDecrypt] 数据解密成功,明文长度: ${plainData.length}`);
return plainData;
} catch (error) {
const err = error as BusinessError;
console.error(`[HuksDecrypt] 解密失败: code=${err.code}, msg=${err.message}`);
return null;
}
}
/**
* 删除密钥
* @param keyAlias 密钥别名
*/
async deleteKey(keyAlias: string): Promise<boolean> {
try {
await huks.deleteKeyItem(keyAlias, { properties: [], inData: new Uint8Array(0) });
console.info(`[HuksKey] 密钥已删除: alias=${keyAlias}`);
return true;
} catch (error) {
const err = error as BusinessError;
console.error(`[HuksKey] 删除密钥失败: ${err.message}`);
return false;
}
}
/**
* 检查密钥是否存在
* @param keyAlias 密钥别名
*/
async isKeyExist(keyAlias: string): Promise<boolean> {
try {
await huks.isKeyItemExist(keyAlias, { properties: [], inData: new Uint8Array(0) });
return true;
} catch {
return false;
}
}
// 辅助方法:Uint8Array转普通数组
private uInt8ArrayToArray(arr: Uint8Array): number[] {
return Array.from(arr);
}
// 辅助方法:提取Nonce(简化实现)
private extractNonce(properties: huks.HuksParam[]): Uint8Array {
// 实际项目中应从初始化结果中获取
const nonce = new Uint8Array(12); // GCM标准Nonce长度
for (let i = 0; i < 12; i++) {
nonce[i] = Math.floor(Math.random() * 256);
}
return nonce;
}
}
/**
* 加密数据结构
*/
interface EncryptedData {
ciphertext: Uint8Array; // 密文
nonce: Uint8Array; // GCM Nonce
aeadTag?: Uint8Array; // AEAD认证标签
}
// 使用示例:加密存储用户敏感数据
async function demoEncryptSensitiveData() {
const keyManager = new HuksKeyManager();
const keyAlias = 'user_payment_key';
// 1. 生成AES密钥(首次使用时)
const keyExists = await keyManager.isKeyExist(keyAlias);
if (!keyExists) {
await keyManager.generateAesKey(keyAlias);
}
// 2. 加密敏感数据
const sensitiveData = new Uint8Array([
// 模拟银行卡号等敏感数据
...Array.from('6222021234567890123', c => c.charCodeAt(0))
]);
const encrypted = await keyManager.encryptData(keyAlias, sensitiveData);
if (encrypted) {
console.info('[Demo] 敏感数据已加密存储');
}
// 3. 解密数据
if (encrypted) {
const decrypted = await keyManager.decryptData(keyAlias, encrypted);
if (decrypted) {
const decryptedStr = String.fromCharCode(...decrypted);
console.info(`[Demo] 解密结果: ${decryptedStr.substring(0, 4)}****`);
}
}
}
3.2 密钥导入导出与签名验签
在某些场景下,你需要从服务器获取密钥并导入 HUKS,或者导出公钥给服务器验证签名。
import { huks } from '@kit.UniversalKeystoreKit';
import { BusinessError } from '@kit.BasicServicesKit';
/**
* 密钥导入导出与签名验签管理器
*/
class HuksSignVerifyManager {
/**
* 导入外部密钥到HUKS
* 注意:导入的密钥会在TEE中重新加密存储
* @param keyAlias 密钥别名
* @param keyData 密钥数据(通常是服务器下发的)
* @param keyType 密钥类型
*/
async importKey(
keyAlias: string,
keyData: Uint8Array,
keyType: 'AES' | 'ECDSA' | 'RSA' = 'ECDSA'
): Promise<boolean> {
try {
let properties: huks.HuksParam[];
switch (keyType) {
case 'AES':
properties = [
{ tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_AES },
{ tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT |
huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT },
{ tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 },
{ tag: huks.HuksTag.HUKS_TAG_PADDING, value: huks.HuksKeyPadding.HUKS_PADDING_PKCS7 },
{ tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, value: huks.HuksCipherMode.HUKS_MODE_GCM },
];
break;
case 'ECDSA':
properties = [
{ tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_ECC },
{ tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_SIGN |
huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_VERIFY },
{ tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_ECC_KEY_SIZE_256 },
{ tag: huks.HuksTag.HUKS_TAG_DIGEST, value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256 },
];
break;
case 'RSA':
properties = [
{ tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_RSA },
{ tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_SIGN |
huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_VERIFY },
{ tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_RSA_KEY_SIZE_2048 },
{ tag: huks.HuksTag.HUKS_TAG_PADDING, value: huks.HuksKeyPadding.HUKS_PADDING_PSS },
{ tag: huks.HuksTag.HUKS_TAG_DIGEST, value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256 },
];
break;
default:
console.error(`[HuksImport] 不支持的密钥类型: ${keyType}`);
return false;
}
const options: huks.HuksOptions = {
properties: properties,
inData: keyData,
};
await huks.importKeyItem(keyAlias, options);
console.info(`[HuksImport] 密钥导入成功: alias=${keyAlias}, type=${keyType}`);
return true;
} catch (error) {
const err = error as BusinessError;
console.error(`[HuksImport] 导入密钥失败: code=${err.code}, msg=${err.message}`);
return false;
}
}
/**
* 导出公钥
* 注意:只能导出公钥,私钥永远不可导出
* @param keyAlias 密钥别名
*/
async exportPublicKey(keyAlias: string): Promise<Uint8Array | null> {
try {
const options: huks.HuksOptions = {
properties: [],
inData: new Uint8Array(0),
};
const result = await huks.exportKeyItem(keyAlias, options);
console.info(`[HuksExport] 公钥导出成功,长度: ${result.outData.length}`);
return result.outData;
} catch (error) {
const err = error as BusinessError;
console.error(`[HuksExport] 导出公钥失败: ${err.message}`);
return null;
}
}
/**
* 使用密钥进行数字签名
* 签名在TEE中完成,私钥永不离开TEE
* @param keyAlias 密钥别名
* @param data 待签名数据
*/
async signData(keyAlias: string, data: Uint8Array): Promise<Uint8Array | null> {
try {
const properties: huks.HuksParam[] = [
{ tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_ECC },
{ tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_SIGN },
{ tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_ECC_KEY_SIZE_256 },
{ tag: huks.HuksTag.HUKS_TAG_DIGEST, value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256 },
];
// 初始化签名会话
const initOptions: huks.HuksOptions = {
properties: properties,
inData: new Uint8Array(0),
};
const handle = await huks.initSession(keyAlias, initOptions);
// 更新待签名数据
const updateOptions: huks.HuksOptions = {
properties: properties,
inData: data,
};
await huks.updateSession(handle.handle, updateOptions);
// 完成签名
const finishOptions: huks.HuksOptions = {
properties: properties,
inData: new Uint8Array(0),
};
const finishResult = await huks.finishSession(handle.handle, finishOptions);
console.info(`[HuksSign] 签名成功,签名长度: ${finishResult.outData.length}`);
return finishResult.outData;
} catch (error) {
const err = error as BusinessError;
console.error(`[HuksSign] 签名失败: code=${err.code}, msg=${err.message}`);
return null;
}
}
/**
* 验证数字签名
* @param keyAlias 密钥别名(或导入的公钥别名)
* @param data 原始数据
* @param signature 待验证的签名
*/
async verifySignature(
keyAlias: string,
data: Uint8Array,
signature: Uint8Array
): Promise<boolean> {
try {
const properties: huks.HuksParam[] = [
{ tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_ECC },
{ tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_VERIFY },
{ tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_ECC_KEY_SIZE_256 },
{ tag: huks.HuksTag.HUKS_TAG_DIGEST, value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256 },
];
// 初始化验签会话
const initOptions: huks.HuksOptions = {
properties: properties,
inData: new Uint8Array(0),
};
const handle = await huks.initSession(keyAlias, initOptions);
// 更新原始数据
const updateOptions: huks.HuksOptions = {
properties: properties,
inData: data,
};
await huks.updateSession(handle.handle, updateOptions);
// 完成验签(传入签名数据)
const finishOptions: huks.HuksOptions = {
properties: properties,
inData: signature,
};
await huks.finishSession(handle.handle, finishOptions);
console.info('[HuksVerify] 签名验证通过');
return true;
} catch (error) {
const err = error as BusinessError;
console.error(`[HuksVerify] 签名验证失败: ${err.message}`);
return false;
}
}
}
// 使用示例:数字签名场景
async function demoDigitalSignature() {
const signManager = new HuksSignVerifyManager();
const keyAlias = 'app_signing_key';
// 1. 生成ECDSA密钥对
const keyManager = new HuksKeyManager();
const keyExists = await keyManager.isKeyExist(keyAlias);
if (!keyExists) {
await keyManager.generateEcdsaKeyPair(keyAlias);
}
// 2. 导出公钥给服务器
const publicKey = await signManager.exportPublicKey(keyAlias);
if (publicKey) {
console.info('[Demo] 公钥已导出,可发送给服务器');
}
// 3. 对数据进行签名
const dataToSign = new Uint8Array([
...Array.from('important_transaction_data', c => c.charCodeAt(0))
]);
const signature = await signManager.signData(keyAlias, dataToSign);
// 4. 验证签名
if (signature) {
const isValid = await signManager.verifySignature(keyAlias, dataToSign, signature);
console.info(`[Demo] 签名验证结果: ${isValid ? '有效' : '无效'}`);
}
}
3.3 密钥绑定用户认证(安全等级配置)
HUKS 最强大的安全特性之一是密钥绑定用户认证——密钥只有在用户通过生物识别或PIN码认证后才能使用。这意味着即使应用被恶意调用,没有用户本人授权,也无法使用密钥。
import { huks } from '@kit.UniversalKeystoreKit';
import { userAuth } from '@kit.UserAuthenticationKit';
import { BusinessError } from '@kit.BasicServicesKit';
/**
* 用户认证绑定密钥管理器
* 密钥使用前必须通过生物识别/PIN认证
*/
class AuthBoundKeyManager {
/**
* 生成绑定用户认证的密钥
* 只有通过指定认证方式后才能使用此密钥
* @param keyAlias 密钥别名
* @param authType 认证类型
* @param secureLevel 安全级别
*/
async generateAuthBoundKey(
keyAlias: string,
authType: userAuth.UserAuthType = userAuth.UserAuthType.FINGERPRINT,
secureLevel: userAuth.AuthTrustLevel = userAuth.AuthTrustLevel.ATL2
): Promise<boolean> {
try {
const properties: huks.HuksParam[] = [
// 基本算法参数
{ tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_AES },
{ tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT |
huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT },
{ tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 },
{ tag: huks.HuksTag.HUKS_TAG_PADDING, value: huks.HuksKeyPadding.HUKS_PADDING_PKCS7 },
{ tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, value: huks.HuksCipherMode.HUKS_MODE_GCM },
// ★ 核心安全配置 ★
// 密钥使用需要用户认证
{ tag: huks.HuksTag.HUKS_TAG_NO_AUTH_REQUIRED, value: false },
// 绑定的认证类型
{ tag: huks.HuksTag.HUKS_TAG_USER_AUTH_TYPE, value: this.mapAuthType(authType) },
// 安全信任级别
{ tag: huks.HuksTag.HUKS_TAG_AUTH_STORAGE_LEVEL, value: this.mapTrustLevel(secureLevel) },
// 认证有效期(秒)- 认证后多久内可以免认证使用密钥
{ tag: huks.HuksTag.HUKS_TAG_AUTH_TIMEOUT, value: 30 }, // 30秒内免认证
];
const options: huks.HuksOptions = {
properties: properties,
inData: new Uint8Array(0),
};
await huks.generateKeyItem(keyAlias, options);
console.info(`[AuthBoundKey] 绑定认证的密钥生成成功: alias=${keyAlias}`);
console.info(`[AuthBoundKey] 认证方式: ${this.getAuthTypeName(authType)}, ` +
`安全级别: ${this.getTrustLevelName(secureLevel)}`);
return true;
} catch (error) {
const err = error as BusinessError;
console.error(`[AuthBoundKey] 生成绑定认证密钥失败: ${err.message}`);
return false;
}
}
/**
* 使用绑定认证的密钥加密数据
* 加密前会自动触发用户认证
* @param keyAlias 密钥别名
* @param plainData 明文数据
*/
async encryptWithAuthBoundKey(
keyAlias: string,
plainData: Uint8Array
): Promise<Uint8Array | null> {
try {
// 1. 先进行用户认证,获取认证令牌
const authToken = await this.requestUserAuth();
if (!authToken) {
console.error('[AuthBoundKey] 用户认证失败,无法使用密钥');
return null;
}
// 2. 初始化加密操作
const properties: huks.HuksParam[] = [
{ tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_AES },
{ tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT },
{ tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 },
{ tag: huks.HuksTag.HUKS_TAG_PADDING, value: huks.HuksKeyPadding.HUKS_PADDING_PKCS7 },
{ tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, value: huks.HuksCipherMode.HUKS_MODE_GCM },
// 传入认证令牌
{ tag: huks.HuksTag.HUKS_TAG_AUTH_TOKEN, value: authToken },
];
const initOptions: huks.HuksOptions = {
properties: properties,
inData: new Uint8Array(0),
};
const handle = await huks.initSession(keyAlias, initOptions);
// 3. 更新数据
const updateOptions: huks.HuksOptions = {
properties: properties,
inData: plainData,
};
const updateResult = await huks.updateSession(handle.handle, updateOptions);
// 4. 完成加密
const finishOptions: huks.HuksOptions = {
properties: properties,
inData: new Uint8Array(0),
};
const finishResult = await huks.finishSession(handle.handle, finishOptions);
// 合并结果
const encrypted = new Uint8Array([
...Array.from(updateResult.outData),
...Array.from(finishResult.outData),
]);
console.info(`[AuthBoundKey] 认证绑定密钥加密成功,密文长度: ${encrypted.length}`);
return encrypted;
} catch (error) {
const err = error as BusinessError;
console.error(`[AuthBoundKey] 认证绑定密钥加密失败: ${err.message}`);
return null;
}
}
/**
* 请求用户认证
* 返回认证令牌供HUKS使用
*/
private async requestUserAuth(): Promise<Uint8Array | null> {
try {
const authRequest: userAuth.UserAuthRequest = {
challenge: this.generateChallenge(),
authType: userAuth.UserAuthType.FINGERPRINT,
trustLevel: userAuth.AuthTrustLevel.ATL2,
};
const authInstance = userAuth.getUserAuthInstance(authRequest);
return new Promise<Uint8Array | null>((resolve) => {
authInstance.on('result', {
onResult(result: userAuth.UserAuthResult, extraInfo?: userAuth.AuthResultInfo) {
if (result === userAuth.UserAuthResult.SUCCESS && extraInfo?.authToken) {
console.info('[AuthBoundKey] 用户认证成功,获取到认证令牌');
resolve(extraInfo.authToken);
} else {
console.error('[AuthBoundKey] 用户认证失败');
resolve(null);
}
}
});
authInstance.start();
});
} catch (error) {
const err = error as BusinessError;
console.error(`[AuthBoundKey] 请求认证异常: ${err.message}`);
return null;
}
}
// 映射认证类型到HUKS常量
private mapAuthType(authType: userAuth.UserAuthType): number {
switch (authType) {
case userAuth.UserAuthType.PIN: return 1 << 0;
case userAuth.UserAuthType.FINGERPRINT: return 1 << 1;
case userAuth.UserAuthType.FACE: return 1 << 2;
default: return 1 << 1; // 默认指纹
}
}
// 映射信任级别到HUKS常量
private mapTrustLevel(level: userAuth.AuthTrustLevel): number {
switch (level) {
case userAuth.AuthTrustLevel.ATL1: return huks.HuksAuthStorageLevel.HUKS_AUTH_STORAGE_LEVEL_LOW;
case userAuth.AuthTrustLevel.ATL2: return huks.HuksAuthStorageLevel.HUKS_AUTH_STORAGE_LEVEL_MEDIUM;
case userAuth.AuthTrustLevel.ATL3: return huks.HuksAuthStorageLevel.HUKS_AUTH_STORAGE_LEVEL_HIGH;
case userAuth.AuthTrustLevel.ATL4: return huks.HuksAuthStorageLevel.HUKS_AUTH_STORAGE_LEVEL_HIGH;
default: return huks.HuksAuthStorageLevel.HUKS_AUTH_STORAGE_LEVEL_MEDIUM;
}
}
private generateChallenge(): string {
const length = 16;
const array = new Uint8Array(length);
for (let i = 0; i < length; i++) {
array[i] = Math.floor(Math.random() * 256);
}
return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
}
private getAuthTypeName(type: userAuth.UserAuthType): string {
switch (type) {
case userAuth.UserAuthType.PIN: return 'PIN码';
case userAuth.UserAuthType.FINGERPRINT: return '指纹';
case userAuth.UserAuthType.FACE: return '人脸';
default: return '未知';
}
}
private getTrustLevelName(level: userAuth.AuthTrustLevel): string {
switch (level) {
case userAuth.AuthTrustLevel.ATL1: return 'S1';
case userAuth.AuthTrustLevel.ATL2: return 'S2';
case userAuth.AuthTrustLevel.ATL3: return 'S3';
case userAuth.AuthTrustLevel.ATL4: return 'S4';
default: return '未知';
}
}
}
// 使用示例:支付密钥绑定指纹认证
async function demoPaymentKeyWithAuth() {
const authBoundManager = new AuthBoundKeyManager();
const keyAlias = 'payment_secure_key';
// 1. 生成绑定指纹认证的支付密钥
await authBoundManager.generateAuthBoundKey(
keyAlias,
userAuth.UserAuthType.FINGERPRINT,
userAuth.AuthTrustLevel.ATL2
);
// 2. 使用密钥加密支付数据(会触发指纹认证)
const paymentData = new Uint8Array([
...Array.from('payment_amount=999.99', c => c.charCodeAt(0))
]);
console.info('[Demo] 即将触发指纹认证以使用支付密钥...');
const encrypted = await authBoundManager.encryptWithAuthBoundKey(keyAlias, paymentData);
if (encrypted) {
console.info('[Demo] 支付数据已加密,用户已通过指纹认证');
} else {
console.warn('[Demo] 支付数据加密失败,用户未通过认证');
}
}
四、踩坑与注意事项
4.1 密钥别名必须唯一
密钥别名是 HUKS 中标识密钥的唯一标识,重复生成会报错:
// ❌ 错误:重复生成同名密钥
await huks.generateKeyItem('my_key', options); // 第一次成功
await huks.generateKeyItem('my_key', options); // 第二次报错!密钥已存在
// ✅ 正确:先检查再生成
async function safeGenerateKey(alias: string, options: huks.HuksOptions) {
try {
await huks.isKeyItemExist(alias, { properties: [], inData: new Uint8Array(0) });
console.info('密钥已存在,跳过生成');
} catch {
// 密钥不存在,生成新密钥
await huks.generateKeyItem(alias, options);
console.info('密钥生成成功');
}
}
4.2 会话必须正确关闭
HUKS 使用三段式操作(init → update → finish/abort),如果中途出错必须调用 abort:
async function safeEncrypt(keyAlias: string, data: Uint8Array): Promise<Uint8Array | null> {
let handle: huks.HuksSessionHandle | null = null;
try {
handle = await huks.initSession(keyAlias, initOptions);
await huks.updateSession(handle.handle, updateOptions);
const result = await huks.finishSession(handle.handle, finishOptions);
return result.outData;
} catch (error) {
// ★ 关键:出错时必须abort,否则会话会泄漏
if (handle) {
try {
await huks.abortSession(handle.handle, { properties: [], inData: new Uint8Array(0) });
console.info('[SafeEncrypt] 会话已中止');
} catch (abortError) {
console.error('[SafeEncrypt] 中止会话也失败了!');
}
}
return null;
}
}
4.3 GCM 模式的 Nonce 管理
AES-GCM 模式的 Nonce(IV)必须每次不同,且需要与密文一起存储:
// ❌ 危险:使用固定Nonce
const fixedNonce = new Uint8Array(12); // 全0,严重不安全
// ✅ 安全:每次加密生成随机Nonce
function generateGcmNonce(): Uint8Array {
const nonce = new Uint8Array(12); // GCM推荐12字节
for (let i = 0; i < 12; i++) {
nonce[i] = Math.floor(Math.random() * 256);
}
return nonce;
}
// Nonce不需要保密,但要和密文一起存储
interface SafeEncryptedData {
nonce: Uint8Array; // 明文存储,解密时需要
ciphertext: Uint8Array; // 密文
aeadTag: Uint8Array; // 认证标签
}
4.4 密钥大小限制
HUKS 对密钥大小有限制,过大的密钥数据会导致导入失败:
| 算法 | 推荐密钥大小 | 最大密钥大小 |
|---|---|---|
| AES | 256位 | 512位 |
| RSA | 2048位 | 4096位 |
| ECC | 256位 | 521位 |
4.5 安全存储级别选择
HUKS 提供三种安全存储级别,需要根据数据敏感度选择:
// 低安全级别:密钥存储在REE文件系统中(加密存储)
// 适用于:非敏感数据
const LOW_LEVEL = huks.HuksAuthStorageLevel.HUKS_AUTH_STORAGE_LEVEL_LOW;
// 中安全级别:密钥存储在TEE中
// 适用于:一般敏感数据(如用户偏好、OAuth令牌)
const MEDIUM_LEVEL = huks.HuksAuthStorageLevel.HUKS_AUTH_STORAGE_LEVEL_MEDIUM;
// 高安全级别:密钥存储在TEE + 硬件安全存储区(RPMB)
// 适用于:高敏感数据(如支付密钥、身份认证密钥)
const HIGH_LEVEL = huks.HuksAuthStorageLevel.HUKS_AUTH_STORAGE_LEVEL_HIGH;
五、HarmonyOS 6 适配
5.1 API 变更
| 变更项 | HarmonyOS 5 | HarmonyOS 6 |
|---|---|---|
| 密钥证明 | attestKeyItem |
新增 attestKeyItemV2 支持设备唯一ID证明 |
| 密钥协商 | 需手动实现ECDH | 新增 agreeKeyItem 原生密钥协商 |
| SM国密算法 | 部分支持 | 全面支持SM2/SM3/SM4 |
| 密钥访问控制 | HUKS_TAG_USER_AUTH_TYPE |
新增 HUKS_TAG_ACCESS_CONTROL 细粒度控制 |
| 安全计算 | 不支持 | 新增 computeSecureHash TEE内哈希计算 |
5.2 迁移指南
// HarmonyOS 5: 手动实现密钥协商
// 需要自己管理ECDH流程...
// HarmonyOS 6: 使用原生密钥协商API
const agreeParams: huks.HuksOptions = {
properties: [
{ tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_ECDH },
{ tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE },
{ tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_ECC_KEY_SIZE_256 },
],
inData: peerPublicKey, // 对端公钥
};
const sharedSecret = await huks.agreeKeyItem(keyAlias, agreeParams);
console.info('[HuksV2] 密钥协商完成');
5.3 国密算法支持
HarmonyOS 6 全面支持中国国密算法:
// HarmonyOS 6: SM2签名
const sm2Params: huks.HuksParam[] = [
{ tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_SM2 },
{ tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_SIGN |
huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_VERIFY },
{ tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_SM2_KEY_SIZE_256 },
{ tag: huks.HuksTag.HUKS_TAG_DIGEST, value: huks.HuksKeyDigest.HUKS_DIGEST_SM3 },
];
// SM4加密
const sm4Params: huks.HuksParam[] = [
{ tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_SM4 },
{ tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT |
huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT },
{ tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128 },
{ tag: huks.HuksTag.HUKS_TAG_PADDING, value: huks.HuksKeyPadding.HUKS_PADDING_PKCS7 },
{ tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, value: huks.HuksCipherMode.HUKS_MODE_CBC },
];
六、总结
核心知识点回顾
安全区域与HUKS
├── 安全架构
│ ├── REE(普通世界)── 应用运行环境,不安全
│ ├── TEE(安全世界)── 密钥生成和运算的安全环境
│ ├── TrustZone ── ARM硬件安全扩展
│ └── RPMB ── 硬件级安全存储区
├── 密钥操作
│ ├── 生成 ── generateKeyItem(密钥在TEE中生成)
│ ├── 导入 ── importKeyItem(外部密钥安全导入)
│ ├── 导出 ── exportKeyItem(仅公钥可导出)
│ ├── 删除 ── deleteKeyItem
│ └── 查询 ── isKeyItemExist
├── 加密运算
│ ├── 初始化 ── initSession
│ ├── 更新数据 ── updateSession(支持分段)
│ ├── 完成 ── finishSession
│ └── 中止 ── abortSession(出错时必须调用)
├── 算法选择
│ ├── AES-256-GCM ── 大量数据加密,性能最佳
│ ├── ECDSA-P256 ── 数字签名,安全高效
│ ├── RSA-2048 ── 密钥交换,兼容性好
│ ├── ECDH-P256 ── 密钥协商,前向保密
│ └── SM2/SM3/SM4 ── 国密算法,合规要求
├── 安全配置
│ ├── 密钥不可导出 ── EXPORTABLE = false
│ ├── 绑定用户认证 ── NO_AUTH_REQUIRED = false
│ ├── 认证类型绑定 ── USER_AUTH_TYPE
│ ├── 安全存储级别 ── AUTH_STORAGE_LEVEL
│ └── 认证有效期 ── AUTH_TIMEOUT
└── 注意事项
├── 别名唯一 ── 重复生成会报错
├── 会话关闭 ── 出错必须abort
├── Nonce管理 ── GCM模式每次随机
├── 密钥大小 ── 不超过算法限制
└── 存储级别 ── 按敏感度选择
HUKS 是 HarmonyOS 安全体系的根基。密钥在 TEE 中生成和运算,永远不会以明文形式暴露给普通世界——这不是一种建议,而是一种保证。理解了 TEE 安全架构、密钥生命周期管理、加密算法选择和用户认证绑定,你就能构建出真正安全的移动应用。记住:安全不是功能,而是基础——就像建筑的钢筋,看不见,但缺了它整栋楼都会塌。
- 点赞
- 收藏
- 关注作者
评论(0)