一文带你了解HarmonyOS开发中的安全区域是什么

举报
Jack20 发表于 2026/06/20 18:33:39 2026/06/20
【摘要】 📌 核心要点:HUKS 是 HarmonyOS 安全体系的根基,密钥在 TEE 中生成和运算,永远不会以明文形式暴露给普通世界 一、背景与动机你有没有想过——手机里存着你的银行卡号、支付密码、指纹数据、聊天记录,这些最敏感的信息,为什么不怕被黑客窃取?答案就是安全区域。安全区域就像银行的金库。普通世界(Rich Execution Environment, REE)是银行的大堂,所有人都能...

📌 核心要点:HUKS 是 HarmonyOS 安全体系的根基,密钥在 TEE 中生成和运算,永远不会以明文形式暴露给普通世界


一、背景与动机

你有没有想过——手机里存着你的银行卡号、支付密码、指纹数据、聊天记录,这些最敏感的信息,为什么不怕被黑客窃取?答案就是安全区域

安全区域就像银行的金库。普通世界(Rich Execution Environment, REE)是银行的大堂,所有人都能进出;安全区域(Trusted Execution Environment, TEE)是金库,只有经过授权的操作才能进入,而且金库里的东西永远不能被带出来。

HarmonyOS 的 HUKS(Universal KeyStore)就是连接普通世界和安全区域的桥梁。它让你的应用可以在 TEE 中生成密钥、存储密钥、使用密钥进行加密解密,而密钥本身永远不会离开 TEE。即使手机被 root、应用被反编译,攻击者也拿不到你的密钥。

这不是什么可选的高级功能——如果你的应用处理支付、身份认证、医疗数据等敏感信息,HUKS 就是你必须掌握的安全基石。


二、核心原理

2.1 TEE 安全架构

图片.png

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 遵循三个核心安全原则:

  1. 密钥永不外泄:密钥在 TEE 中生成,加密运算在 TEE 中完成,密钥明文永远不会出现在 REE 中
  2. 访问控制严格:密钥可以绑定用户认证(指纹/PIN),只有通过认证才能使用密钥
  3. 安全存储可靠:密钥材料存储在 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 安全架构、密钥生命周期管理、加密算法选择和用户认证绑定,你就能构建出真正安全的移动应用。记住:安全不是功能,而是基础——就像建筑的钢筋,看不见,但缺了它整栋楼都会塌。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。