数据库加密:HarmonyOS开发安全存储实践

📌 核心要点:数据库加密是应用安全的重要防线,HarmonyOS通过RDB加密和HUKS密钥管理,实现透明且安全的数据存储

一、背景与动机

数据泄露的新闻你肯定没少见——某某App用户数据泄露、某某公司数据库被拖库……这些事故背后,往往都有一个共同原因:敏感数据明文存储。

你想想,用户手机丢了,或者被恶意软件读取数据目录,如果你的数据库里存着用户的支付密码、聊天记录、身份证号,而且全是明文,那后果简直不敢想。这就是为什么数据库加密不是"锦上添花",而是"必备技能"。

HarmonyOS在这方面做得挺到位——RDB数据库原生支持加密,而且跟HUKS(HarmonyOS Universal Key Store)深度集成。说白了,你不用自己操心密钥怎么存、怎么防窃取,系统帮你搞定一切。加密过程对应用透明,该CRUD还是CRUD,完全感知不到加密的存在。

二、核心原理

2.1 加密架构

HarmonyOS数据库加密采用分层架构:

graph TD
    A[应用层]:::primary --> B[RDB API]
    B --> C{加密开关判断}
    C -->|已启用加密| D[加密引擎]
    C -->|未启用| E[直接存储]
    D --> F[HUKS密钥管理]
    F --> G[密钥生成]
    F --> H[密钥存储]
    F --> I[密钥访问控制]
    D --> J[数据加密/解密]
    J --> K[加密数据库文件]
    E --> L[明文数据库文件]
    K --> M[磁盘存储]
    L --> M
    
    classDef primary fill:#4CAF50,stroke:#388E3C,color:#fff
    classDef warning fill:#FF9800,stroke:#F57C00,color:#fff
    classDef info fill:#2196F3,stroke:#1976D2,color:#fff

2.2 加密流程

当创建加密数据库时,系统会自动完成以下步骤:

  1. 密钥生成:调用HUKS生成AES-256密钥
  2. 密钥派生:基于用户密码派生数据库加密密钥
  3. 数据库初始化:SQLite层设置加密参数
  4. 透明加密:写入时自动加密,读取时自动解密

2.3 HUKS安全机制

HUKS是HarmonyOS的安全核心,提供硬件级密钥保护:

特性说明安全等级
密钥隔离密钥存储在TEE(可信执行环境)硬件级
访问控制只有授权应用才能使用密钥系统级
防导出密钥无法被导出或读取硬件级
防篡改密钥元数据完整性保护硬件级

2.4 加密算法

HarmonyOS RDB加密默认采用:

  • 加密算法:AES-256-GCM
  • 密钥长度:256位
  • 工作模式:GCM(提供认证加密)
  • 密钥派生:PBKDF2(基于用户密码)

三、代码实战

3.1 基础用法:创建加密数据库

最简单的加密方式——创建数据库时指定加密密钥。

import relationalStore from '@ohos.data.relationalStore';

@Entry
@Component
struct EncryptedDBBasic {
  private rdbStore: relationalStore.RdbStore | null = null;
  
  async aboutToAppear(): Promise<void> {
    await this.createEncryptedDB();
  }
  
  // 创建加密数据库
  async createEncryptedDB(): Promise<void> {
    try {
      // 数据库配置
      const config: relationalStore.StoreConfig = {
        name: 'SecureData.db',
        securityLevel: relationalStore.SecurityLevel.S3,  // S3级别:敏感数据
      };
      
      // 加密密钥(实际项目应从HUKS获取)
      const encryptKey = 'user_password_123456';
      
      // 创建加密数据库
      this.rdbStore = await relationalStore.getRdbStore(
        getContext(this),
        config,
        encryptKey  // 传入加密密钥
      );
      
      console.info('[加密数据库] 创建成功');
      
      // 创建表
      await this.createTables();
      
    } catch (error) {
      console.error(`[加密数据库] 创建失败: ${JSON.stringify(error)}`);
    }
  }
  
  // 创建数据表
  async createTables(): Promise<void> {
    if (!this.rdbStore) return;
    
    const createTableSQL = `
      CREATE TABLE IF NOT EXISTS user_secrets (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        category TEXT NOT NULL,
        content TEXT NOT NULL,
        created_time INTEGER NOT NULL
      )
    `;
    
    await this.rdbStore.executeSql(createTableSQL);
    console.info('[数据表] 创建成功');
  }
  
  // 插入敏感数据
  async insertSecret(category: string, content: string): Promise<void> {
    if (!this.rdbStore) return;
    
    const valueBucket: relationalStore.ValuesBucket = {
      category: category,
      content: content,
      created_time: Date.now()
    };
    
    try {
      const rowId = await this.rdbStore.insert('user_secrets', valueBucket);
      console.info(`[插入数据] 成功,rowId: ${rowId}`);
    } catch (error) {
      console.error(`[插入数据] 失败: ${JSON.stringify(error)}`);
    }
  }
  
  build() {
    Column() {
      Text('加密数据库基础示例')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
      
      Button('插入测试数据')
        .margin({ top: 20 })
        .onClick(() => {
          this.insertSecret('密码', 'my_bank_password_123');
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

3.2 进阶用法:HUKS密钥管理

生产环境中,密钥不能硬编码,必须通过HUKS管理。

import huks from '@ohos.security.huks';
import relationalStore from '@ohos.data.relationalStore';

@Entry
@Component
struct HUKSEncryption {
  @State keyAlias: string = 'db_encrypt_key_v1';
  @State dbStatus: string = '未初始化';
  private rdbStore: relationalStore.RdbStore | null = null;
  
  // 初始化HUKS密钥
  async initHUKSKey(): Promise<boolean> {
    try {
      // 检查密钥是否已存在
      const isExist = await this.checkKeyExist(this.keyAlias);
      
      if (!isExist) {
        // 生成新密钥
        await this.generateKey(this.keyAlias);
        console.info('[HUKS] 密钥生成成功');
      } else {
        console.info('[HUKS] 密钥已存在');
      }
      
      return true;
      
    } catch (error) {
      console.error(`[HUKS] 初始化失败: ${JSON.stringify(error)}`);
      return false;
    }
  }
  
  // 检查密钥是否存在
  async checkKeyExist(keyAlias: string): Promise<boolean> {
    const options: huks.HuksOptions = {
      properties: [
        { tag: huks.HuksTag.HUKS_TAG_STORAGE_FLAG, value: huks.HuksKeyStorageFlag.HUKS_STORAGE_PERSISTENT }
      ]
    };
    
    try {
      await huks.isKeyItemExist(keyAlias, options);
      return true;
    } catch (error) {
      return false;
    }
  }
  
  // 生成加密密钥
  async generateKey(keyAlias: string): Promise<void> {
    const properties: huks.HuksParam[] = [
      { tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_AES },
      { tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 },
      { tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT },
      { tag: huks.HuksTag.HUKS_TAG_PADDING, value: huks.HuksKeyPadding.HUKS_PADDING_NONE },
      { tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, value: huks.HuksKeyMode.HUKS_MODE_GCM },
      { tag: huks.HuksTag.HUKS_TAG_STORAGE_FLAG, value: huks.HuksKeyStorageFlag.HUKS_STORAGE_PERSISTENT },
      // 访问控制:需要用户认证
      { tag: huks.HuksTag.HUKS_TAG_USER_AUTH_TYPE, value: huks.HuksUserAuthType.HUKS_USER_AUTH_TYPE_FINGERPRINT | huks.HuksUserAuthType.HUKS_USER_AUTH_TYPE_PIN },
      { tag: huks.HuksTag.HUKS_TAG_KEY_AUTH_ACCESS_TYPE, value: huks.HuksAuthAccessType.HUKS_AUTH_ACCESS_INVALID_CLEAR_PASSWORD }
    ];
    
    const options: huks.HuksOptions = { properties: properties };
    
    await huks.generateKeyItem(keyAlias, options);
  }
  
  // 使用HUKS密钥创建加密数据库
  async createDBWithHUKS(): Promise<void> {
    try {
      this.dbStatus = '初始化中...';
      
      // 1. 初始化HUKS密钥
      const keyReady = await this.initHUKSKey();
      if (!keyReady) {
        this.dbStatus = '密钥初始化失败';
        return;
      }
      
      // 2. 从HUKS导出密钥(用于数据库加密)
      const dbKey = await this.exportDBKey(this.keyAlias);
      
      // 3. 创建加密数据库
      const config: relationalStore.StoreConfig = {
        name: 'HUKS_Encrypted.db',
        securityLevel: relationalStore.SecurityLevel.S4,  // 最高安全级别
      };
      
      this.rdbStore = await relationalStore.getRdbStore(getContext(this), config, dbKey);
      
      this.dbStatus = '数据库就绪';
      console.info('[数据库] 加密数据库创建成功');
      
    } catch (error) {
      this.dbStatus = '初始化失败';
      console.error(`[数据库] 创建失败: ${JSON.stringify(error)}`);
    }
  }
  
  // 导出数据库加密密钥
  private async exportDBKey(keyAlias: string): Promise<string> {
    // 实际项目中,这里应该使用HUKS的密钥派生功能
    // 从主密钥派生出数据库专用密钥
    
    const properties: huks.HuksParam[] = [
      { tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_AES },
      { tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 },
      { tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT }
    ];
    
    const options: huks.HuksOptions = { properties: properties };
    
    // 导出公钥(注意:实际密钥不可导出,这里导出的是派生密钥)
    const result = await huks.exportKeyItem(keyAlias, options);
    
    // 将密钥数据转换为字符串
    const keyData = result.outData;
    return this.arrayBufferToString(keyData);
  }
  
  // ArrayBuffer转字符串
  private arrayBufferToString(buffer: ArrayBuffer): string {
    const uint8Array = new Uint8Array(buffer);
    let result = '';
    for (let i = 0; i < uint8Array.length; i++) {
      result += String.fromCharCode(uint8Array[i]);
    }
    return result;
  }
  
  // 加密敏感数据(双重加密)
  async encryptSensitiveData(plainText: string): Promise<string> {
    try {
      // 准备加密参数
      const properties: huks.HuksParam[] = [
        { tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_AES },
        { tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 },
        { tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT },
        { tag: huks.HuksTag.HUKS_TAG_PADDING, value: huks.HuksKeyPadding.HUKS_PADDING_NONE },
        { tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, value: huks.HuksKeyMode.HUKS_MODE_GCM },
        { tag: huks.HuksTag.HUKS_TAG_NONCE, value: this.generateNonce(12) },  // GCM需要12字节nonce
        { tag: huks.HuksTag.HUKS_TAG_ASSOCIATED_DATA, value: new Uint8Array(0) }  // 附加数据
      ];
      
      const options: huks.HuksOptions = {
        properties: properties,
        inData: this.stringToArrayBuffer(plainText)
      };
      
      // 执行加密
      const result = await huks.finish(this.keyAlias, options);
      
      // 返回Base64编码的密文
      return this.arrayBufferToBase64(result.outData);
      
    } catch (error) {
      console.error(`[加密] 失败: ${JSON.stringify(error)}`);
      throw error;
    }
  }
  
  // 解密数据
  async decryptSensitiveData(cipherText: string): Promise<string> {
    try {
      const properties: huks.HuksParam[] = [
        { tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_AES },
        { tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 },
        { tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT },
        { tag: huks.HuksTag.HUKS_TAG_PADDING, value: huks.HuksKeyPadding.HUKS_PADDING_NONE },
        { tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, value: huks.HuksKeyMode.HUKS_MODE_GCM },
        { tag: huks.HuksTag.HUKS_TAG_NONCE, value: this.generateNonce(12) }
      ];
      
      const options: huks.HuksOptions = {
        properties: properties,
        inData: this.base64ToArrayBuffer(cipherText)
      };
      
      const result = await huks.finish(this.keyAlias, options);
      return this.arrayBufferToString(result.outData);
      
    } catch (error) {
      console.error(`[解密] 失败: ${JSON.stringify(error)}`);
      throw error;
    }
  }
  
  // 生成随机Nonce
  private generateNonce(length: number): Uint8Array {
    const nonce = new Uint8Array(length);
    for (let i = 0; i < length; i++) {
      nonce[i] = Math.floor(Math.random() * 256);
    }
    return nonce;
  }
  
  // 字符串转ArrayBuffer
  private stringToArrayBuffer(str: string): ArrayBuffer {
    const buffer = new ArrayBuffer(str.length);
    const view = new Uint8Array(buffer);
    for (let i = 0; i < str.length; i++) {
      view[i] = str.charCodeAt(i);
    }
    return buffer;
  }
  
  // ArrayBuffer转Base64
  private arrayBufferToBase64(buffer: ArrayBuffer): string {
    const bytes = new Uint8Array(buffer);
    let binary = '';
    for (let i = 0; i < bytes.length; i++) {
      binary += String.fromCharCode(bytes[i]);
    }
    return btoa(binary);
  }
  
  // Base64转ArrayBuffer
  private base64ToArrayBuffer(base64: string): ArrayBuffer {
    const binary = atob(base64);
    const buffer = new ArrayBuffer(binary.length);
    const view = new Uint8Array(buffer);
    for (let i = 0; i < binary.length; i++) {
      view[i] = binary.charCodeAt(i);
    }
    return buffer;
  }
  
  build() {
    Column({ space: 20 }) {
      Text('HUKS密钥管理示例')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
      
      Text(`状态: ${this.dbStatus}`)
        .fontSize(16)
      
      Button('初始化加密数据库')
        .width('80%')
        .onClick(() => this.createDBWithHUKS())
      
      Button('加密测试数据')
        .width('80%')
        .onClick(async () => {
          const encrypted = await this.encryptSensitiveData('我的银行卡密码');
          console.info(`[加密结果] ${encrypted}`);
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

3.3 完整示例:密码管理器

来个实战场景——一个安全的密码管理器。

import relationalStore from '@ohos.data.relationalStore';
import huks from '@ohos.security.huks';
import cryptoFramework from '@ohos.security.cryptoFramework';

@Entry
@Component
struct PasswordManager {
  @State passwords: PasswordEntry[] = [];
  @State isUnlocked: boolean = false;
  @State masterPassword: string = '';
  
  private rdbStore: relationalStore.RdbStore | null = null;
  private keyAlias: string = 'pwd_mgr_master_key';
  
  // 初始化密码管理器
  async initPasswordManager(): Promise<void> {
    try {
      // 生成或获取主密钥
      await this.ensureMasterKey();
      
      // 创建加密数据库
      const config: relationalStore.StoreConfig = {
        name: 'PasswordVault.db',
        securityLevel: relationalStore.SecurityLevel.S4
      };
      
      // 使用主密码派生数据库密钥
      const dbKey = await this.deriveDBKey(this.masterPassword);
      
      this.rdbStore = await relationalStore.getRdbStore(getContext(this), config, dbKey);
      
      // 创建密码表
      await this.createPasswordTable();
      
      this.isUnlocked = true;
      await this.loadPasswords();
      
      console.info('[密码管理器] 初始化成功');
      
    } catch (error) {
      console.error(`[密码管理器] 初始化失败: ${JSON.stringify(error)}`);
    }
  }
  
  // 确保主密钥存在
  async ensureMasterKey(): Promise<void> {
    const options: huks.HuksOptions = {
      properties: [
        { tag: huks.HuksTag.HUKS_TAG_STORAGE_FLAG, value: huks.HuksKeyStorageFlag.HUKS_STORAGE_PERSISTENT }
      ]
    };
    
    try {
      await huks.isKeyItemExist(this.keyAlias, options);
    } catch (error) {
      // 密钥不存在,创建新密钥
      await this.createMasterKey();
    }
  }
  
  // 创建主密钥
  async createMasterKey(): Promise<void> {
    const properties: huks.HuksParam[] = [
      { tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_AES },
      { tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 },
      { tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT },
      { tag: huks.HuksTag.HUKS_TAG_PADDING, value: huks.HuksKeyPadding.HUKS_PADDING_PKCS7 },
      { tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, value: huks.HuksKeyMode.HUKS_MODE_CBC },
      { tag: huks.HuksTag.HUKS_TAG_STORAGE_FLAG, value: huks.HuksKeyStorageFlag.HUKS_STORAGE_PERSISTENT },
      // 生物认证保护
      { tag: huks.HuksTag.HUKS_TAG_USER_AUTH_TYPE, value: huks.HuksUserAuthType.HUKS_USER_AUTH_TYPE_FINGERPRINT },
      { tag: huks.HuksTag.HUKS_TAG_KEY_AUTH_ACCESS_TYPE, value: huks.HuksAuthAccessType.HUKS_AUTH_ACCESS_INVALID_NEW_BIO_ENROLL }
    ];
    
    await huks.generateKeyItem(this.keyAlias, { properties });
  }
  
  // 派生数据库密钥
  async deriveDBKey(masterPassword: string): Promise<string> {
    // 使用PBKDF2从主密码派生密钥
    const salt = 'password_manager_salt_v1';
    const iterations = 10000;
    const keyLen = 32;  // 256位
    
    try {
      // 创建PBKDF2密钥派生器
      const kdf = cryptoFramework.createKdf('PBKDF2|SHA256');
      
      const params: cryptoFramework.PBKDF2Spec = {
        algName: 'PBKDF2',
        password: masterPassword,
        salt: salt,
        iterations: iterations,
        keySize: keyLen
      };
      
      const deriveKey = await kdf.generateKey(params);
      return deriveKey.getEncoded().data;
      
    } catch (error) {
      console.error(`[密钥派生] 失败: ${JSON.stringify(error)}`);
      // 降级方案:直接使用主密码
      return masterPassword;
    }
  }
  
  // 创建密码表
  async createPasswordTable(): Promise<void> {
    if (!this.rdbStore) return;
    
    const sql = `
      CREATE TABLE IF NOT EXISTS passwords (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        site_name TEXT NOT NULL,
        site_url TEXT,
        username TEXT NOT NULL,
        encrypted_password BLOB NOT NULL,
        notes TEXT,
        category TEXT DEFAULT 'default',
        created_time INTEGER NOT NULL,
        updated_time INTEGER NOT NULL,
        iv BLOB NOT NULL
      )
    `;
    
    await this.rdbStore.executeSql(sql);
  }
  
  // 添加密码条目
  async addPassword(entry: PasswordInput): Promise<void> {
    if (!this.rdbStore) return;
    
    try {
      // 加密密码
      const { encrypted, iv } = await this.encryptPassword(entry.password);
      
      const valueBucket: relationalStore.ValuesBucket = {
        site_name: entry.siteName,
        site_url: entry.siteUrl || '',
        username: entry.username,
        encrypted_password: encrypted,
        notes: entry.notes || '',
        category: entry.category || 'default',
        created_time: Date.now(),
        updated_time: Date.now(),
        iv: iv
      };
      
      const rowId = await this.rdbStore.insert('passwords', valueBucket);
      console.info(`[密码] 添加成功,ID: ${rowId}`);
      
      await this.loadPasswords();
      
    } catch (error) {
      console.error(`[密码] 添加失败: ${JSON.stringify(error)}`);
    }
  }
  
  // 加密密码
  private async encryptPassword(plainPassword: string): Promise<{ encrypted: ArrayBuffer, iv: ArrayBuffer }> {
    // 生成随机IV
    const iv = new Uint8Array(16);
    for (let i = 0; i < 16; i++) {
      iv[i] = Math.floor(Math.random() * 256);
    }
    
    const properties: huks.HuksParam[] = [
      { tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_AES },
      { tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 },
      { tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT },
      { tag: huks.HuksTag.HUKS_TAG_PADDING, value: huks.HuksKeyPadding.HUKS_PADDING_PKCS7 },
      { tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, value: huks.HuksKeyMode.HUKS_MODE_CBC },
      { tag: huks.HuksTag.HUKS_TAG_IV, value: iv }
    ];
    
    const inData = new TextEncoder().encode(plainPassword);
    const options: huks.HuksOptions = { properties, inData };
    
    const result = await huks.finish(this.keyAlias, options);
    
    return {
      encrypted: result.outData,
      iv: iv.buffer
    };
  }
  
  // 解密密码
  async decryptPassword(entry: PasswordEntry): Promise<string> {
    const properties: huks.HuksParam[] = [
      { tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_AES },
      { tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 },
      { tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT },
      { tag: huks.HuksTag.HUKS_TAG_PADDING, value: huks.HuksKeyPadding.HUKS_PADDING_PKCS7 },
      { tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, value: huks.HuksKeyMode.HUKS_MODE_CBC },
      { tag: huks.HuksTag.HUKS_TAG_IV, value: new Uint8Array(entry.iv) }
    ];
    
    const options: huks.HuksOptions = {
      properties,
      inData: entry.encryptedPassword
    };
    
    const result = await huks.finish(this.keyAlias, options);
    return new TextDecoder().decode(result.outData);
  }
  
  // 加载密码列表(不解密)
  async loadPasswords(): Promise<void> {
    if (!this.rdbStore) return;
    
    const predicates = new relationalStore.RdbPredicates('passwords');
    predicates.orderByDesc('updated_time');
    
    const resultSet = await this.rdbStore.query(predicates);
    
    this.passwords = [];
    while (resultSet.goToNextRow()) {
      this.passwords.push({
        id: resultSet.getLong(resultSet.getColumnIndex('id')),
        siteName: resultSet.getString(resultSet.getColumnIndex('site_name')),
        siteUrl: resultSet.getString(resultSet.getColumnIndex('site_url')),
        username: resultSet.getString(resultSet.getColumnIndex('username')),
        encryptedPassword: resultSet.getBlob(resultSet.getColumnIndex('encrypted_password')),
        notes: resultSet.getString(resultSet.getColumnIndex('notes')),
        category: resultSet.getString(resultSet.getColumnIndex('category')),
        createdTime: resultSet.getLong(resultSet.getColumnIndex('created_time')),
        updatedTime: resultSet.getLong(resultSet.getColumnIndex('updated_time')),
        iv: resultSet.getBlob(resultSet.getColumnIndex('iv'))
      });
    }
    
    resultSet.close();
  }
  
  // 删除密码
  async deletePassword(id: number): Promise<void> {
    if (!this.rdbStore) return;
    
    const predicates = new relationalStore.RdbPredicates('passwords');
    predicates.equalTo('id', id);
    
    const deletedRows = await this.rdbStore.delete(predicates);
    console.info(`[密码] 删除 ${deletedRows} 条记录`);
    
    await this.loadPasswords();
  }
  
  build() {
    Column({ space: 16 }) {
      // 标题
      Row() {
        Text('密码管理器')
          .fontSize(24)
          .fontWeight(FontWeight.Bold)
        
        Blank()
        
        if (this.isUnlocked) {
          Badge({ count: this.passwords.length, style: { badgeSize: 20, badgeColor: '#4CAF50' } }) {
            Icon($r('app.media.ic_lock'))
              .width(24)
              .height(24)
          }
        }
      }
      .width('100%')
      .padding({ left: 20, right: 20 })
      
      if (!this.isUnlocked) {
        // 解锁界面
        Column({ space: 16 }) {
          TextInput({ placeholder: '请输入主密码' })
            .type(InputType.Password)
            .width('80%')
            .onChange((value) => this.masterPassword = value)
          
          Button('解锁')
            .width('80%')
            .onClick(() => this.initPasswordManager())
        }
        .layoutWeight(1)
        .justifyContent(FlexAlign.Center)
        
      } else {
        // 密码列表
        List({ space: 12 }) {
          ForEach(this.passwords, (item: PasswordEntry) => {
            ListItem() {
              PasswordCard({
                entry: item,
                onDecrypt: async () => {
                  const pwd = await this.decryptPassword(item);
                  console.info(`[解密密码] ${pwd}`);
                  // 实际项目中应显示在UI或复制到剪贴板
                },
                onDelete: () => this.deletePassword(item.id)
              })
            }
          }, (item: PasswordEntry) => item.id.toString())
        }
        .width('100%')
        .layoutWeight(1)
        .padding({ left: 16, right: 16 })
        
        // 添加按钮
        Button('添加密码')
          .width('90%')
          .onClick(() => {
            // 实际项目中应弹出添加界面
            this.addPassword({
              siteName: '示例网站',
              siteUrl: 'https://example.com',
              username: 'user@example.com',
              password: 'MySecurePassword123!',
              category: 'work'
            });
          })
      }
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
  }
}

// 密码卡片组件
@Component
struct PasswordCard {
  @Prop entry: PasswordEntry;
  onDecrypt: () => void = () => {};
  onDelete: () => void = () => {};
  
  build() {
    Column({ space: 8 }) {
      Row() {
        Text(this.entry.siteName)
          .fontSize(18)
          .fontWeight(FontWeight.Medium)
        
        Blank()
        
        Text(this.entry.category)
          .fontSize(12)
          .fontColor('#666')
          .padding({ left: 8, right: 8, top: 2, bottom: 2 })
          .backgroundColor('#E0E0E0')
          .borderRadius(4)
      }
      .width('100%')
      
      Text(this.entry.username)
        .fontSize(14)
        .fontColor('#666')
      
      Row({ space: 12 }) {
        Button('查看密码')
          .fontSize(12)
          .height(32)
          .onClick(() => this.onDecrypt())
        
        Button('删除')
          .fontSize(12)
          .height(32)
          .backgroundColor('#FF5722')
          .onClick(() => this.onDelete())
      }
    }
    .width('100%')
    .padding(16)
    .backgroundColor(Color.White)
    .borderRadius(12)
  }
}

// 数据结构
interface PasswordEntry {
  id: number;
  siteName: string;
  siteUrl: string;
  username: string;
  encryptedPassword: ArrayBuffer;
  notes: string;
  category: string;
  createdTime: number;
  updatedTime: number;
  iv: ArrayBuffer;
}

interface PasswordInput {
  siteName: string;
  siteUrl?: string;
  username: string;
  password: string;
  notes?: string;
  category?: string;
}

四、踩坑与注意事项

4.1 密钥管理陷阱

坑点:密钥硬编码或存储在配置文件中,形同虚设。

解决方案:必须使用HUKS管理密钥,利用硬件级安全保护。

// ❌ 错误做法
const SECRET_KEY = 'hardcoded_key_123456';  // 完全不安全

// ✅ 正确做法
const keyAlias = 'app_master_key';
await huks.generateKeyItem(keyAlias, secureOptions);

4.2 加密性能问题

坑点:频繁加解密操作导致性能下降。

解决方案:使用缓存策略,避免重复解密。

// 密码缓存(内存中暂存解密后的数据)
private passwordCache: Map<number, string> = new Map();

async getPassword(id: number): Promise<string> {
  // 先查缓存
  if (this.passwordCache.has(id)) {
    return this.passwordCache.get(id)!;
  }
  
  // 缓存未命中,执行解密
  const entry = await this.getPasswordEntry(id);
  const decrypted = await this.decryptPassword(entry);
  
  // 存入缓存(设置过期时间)
  this.passwordCache.set(id, decrypted);
  setTimeout(() => this.passwordCache.delete(id), 60000);  // 1分钟后清除
  
  return decrypted;
}

4.3 数据库迁移问题

坑点:从非加密数据库迁移到加密数据库,或更换密钥时数据丢失。

解决方案:实现安全迁移流程。

async function migrateToEncryptedDB(): Promise<void> {
  // 1. 打开原数据库
  const oldDB = await relationalStore.getRdbStore(context, { name: 'OldData.db' });
  
  // 2. 导出所有数据
  const data = await exportAllData(oldDB);
  
  // 3. 创建加密数据库
  const newDB = await relationalStore.getRdbStore(context, { name: 'EncryptedData.db' }, encryptKey);
  
  // 4. 导入数据
  await importAllData(newDB, data);
  
  // 5. 安全删除原数据库
  await relationalStore.deleteRdbStore(context, 'OldData.db');
}

4.4 密钥丢失处理

坑点:用户忘记主密码或密钥损坏,数据无法恢复。

解决方案:提供密钥恢复机制或数据备份。

// 密钥恢复提示
async function setupRecoveryHint(): Promise<void> {
  // 生成恢复提示(不能直接暴露密钥)
  const hint = await generateSecureHint(masterPassword);
  
  // 加密存储提示
  const encryptedHint = await encryptWithDeviceKey(hint);
  await saveToSecureStorage('recovery_hint', encryptedHint);
}

4.5 安全级别选择

坑点:安全级别设置不当,影响加密强度。

最佳实践

// 根据数据敏感度选择安全级别
const securityLevel = {
  // S1:普通数据(用户设置、缓存)
  normal: relationalStore.SecurityLevel.S1,
  
  // S2:个人信息(昵称、头像)
  personal: relationalStore.SecurityLevel.S2,
  
  // S3:敏感数据(聊天记录、位置)
  sensitive: relationalStore.SecurityLevel.S3,
  
  // S4:高度敏感(密码、支付信息)
  critical: relationalStore.SecurityLevel.S4
};

五、HarmonyOS 6适配说明

HarmonyOS 6在数据库加密方面带来了显著增强:

5.1 新增特性

  1. 硬件加密加速:利用TEE加速加密运算,性能提升40%+
  2. 多密钥支持:同一数据库支持多个加密密钥,不同表可用不同密钥
  3. 密钥轮换:支持在线密钥轮换,无需停机
  4. 审计日志:加密操作自动记录审计日志

5.2 API变更

新增API

// 密钥轮换
await rdbStore.rotateEncryptionKey(oldKey, newKey);

// 获取加密状态
const status = await rdbStore.getEncryptionStatus();
console.info(`加密算法: ${status.algorithm}`);
console.info(`密钥长度: ${status.keySize}`);

// 设置表级加密密钥
await rdbStore.setTableEncryptionKey('sensitive_table', specificKey);

废弃API

  • setEncryptKey():改用getRdbStore()的密钥参数

5.3 适配代码示例

import relationalStore from '@ohos.data.relationalStore';
import huks from '@ohos.security.huks';

// HarmonyOS 6加密数据库初始化
async function initEncryptedDB_HarmonyOS6(): Promise<void> {
  // 生成主密钥(支持生物认证)
  const masterKeyAlias = 'master_key_v2';
  const masterKeyOptions: huks.HuksOptions = {
    properties: [
      { tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_AES },
      { tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 },
      { tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT },
      { tag: huks.HuksTag.HUKS_TAG_DIGEST, value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256 },
      // HarmonyOS 6新增:安全世界标志
      { tag: huks.HuksTag.HUKS_TAG_IS_KEY_SECURE, value: true },
      // 用户认证要求
      { tag: huks.HuksTag.HUKS_TAG_USER_AUTH_TYPE, value: huks.HuksUserAuthType.HUKS_USER_AUTH_TYPE_FINGERPRINT | huks.HuksUserAuthType.HUKS_USER_AUTH_TYPE_FACE },
      { tag: huks.HuksTag.HUKS_TAG_KEY_AUTH_ACCESS_TYPE, value: huks.HuksAuthAccessType.HUKS_AUTH_ACCESS_INVALID_NEW_BIO_ENROLL },
      // HarmonyOS 6新增:认证超时
      { tag: huks.HuksTag.HUKS_TAG_AUTH_TIMEOUT, value: 30 }  // 30秒认证窗口
    ]
  };
  
  await huks.generateKeyItem(masterKeyAlias, masterKeyOptions);
  
  // 创建加密数据库
  const dbConfig: relationalStore.StoreConfig = {
    name: 'SecureApp.db',
    securityLevel: relationalStore.SecurityLevel.S4,
    // HarmonyOS 6新增:加密配置
    encryptConfig: {
      enableHardwareAcceleration: true,  // 启用硬件加速
      enableAuditLog: true,              // 启用审计日志
      keyRotationInterval: 7776000000    // 密钥轮换间隔:90天
    }
  };
  
  const rdbStore = await relationalStore.getRdbStore(getContext(), dbConfig, masterKeyAlias);
  
  // 检查加密状态
  const encryptStatus = await rdbStore.getEncryptionStatus();
  console.info(`[加密状态] 算法: ${encryptStatus.algorithm}`);
  console.info(`[加密状态] 硬件加速: ${encryptStatus.hardwareAccelerated}`);
  
  // 设置表级加密(敏感数据表使用独立密钥)
  const sensitiveKeyAlias = 'sensitive_table_key';
  await huks.generateKeyItem(sensitiveKeyAlias, masterKeyOptions);
  await rdbStore.setTableEncryptionKey('user_passwords', sensitiveKeyAlias);
}

5.4 性能优化建议

HarmonyOS 6环境下,充分利用硬件加速:

// 性能优化配置
const performanceConfig = {
  // 启用硬件加速(必须)
  enableHardwareAcceleration: true,
  
  // 批量加密优化
  batchSize: 100,  // 每批加密100条
  
  // 缓存策略
  enableDecryptionCache: true,
  cacheSize: 50,  // 缓存50条解密结果
  
  // 预解密策略(UI显示前预解密)
  enablePreDecryption: true
};

六、总结

维度评价
学习难度⭐⭐⭐⭐
使用频率⭐⭐⭐
重要程度⭐⭐⭐⭐⭐
调试难度⭐⭐⭐⭐

核心收获

  1. 数据库加密是应用安全的底线,涉及敏感数据必须加密,这是原则问题
  2. HUKS是密钥管理的正确姿势,利用硬件级安全保护,避免密钥泄露
  3. 透明加密让开发无感知,加密后的数据库使用方式完全不变
  4. 密钥管理比加密算法更重要,密钥泄露了,再强的加密也没用
  5. HarmonyOS 6的硬件加速是重大利好,性能不再是加密的借口

下一步建议

  • 学习HUKS的高级特性:密钥协商、签名验签
  • 研究分布式场景下的密钥同步问题
  • 探索端到端加密在即时通讯中的应用
  • 实现密钥托管和恢复机制

蓝胖子样样好
79 声望702 粉丝

Never give up,and you will be successful