HarmonyOS鸿蒙Next中APP如何实现敏感数据(如密码)的AES加密存储?

HarmonyOS鸿蒙Next中APP如何实现敏感数据(如密码)的AES加密存储?

问题描述

开发登录功能时,需要将用户密码存储在本地,避免明文存储导致安全风险,想使用 AES 加密,但不知道鸿蒙原生如何实现 AES 加密 / 解密,加密后的密钥如何安全存储?是否有现成的 API 可用?关键字:鸿蒙 AES 加密、敏感数据存储、密码加密、安全存储、cryptoFramework

回答内容

原理解析

鸿蒙提供@ohos.security.cryptoFramework框架,支持 AES、RSA 等加密算法,AES 加密适合敏感数据(如密码)的本地存储:

  • 采用 AES-GCM 模式(带认证的加密,更安全),避免 ECB 模式的安全隐患;
  • 密钥需通过鸿蒙 “安全存储”(如 KeyStore)保存,不能硬编码在代码中;
  • 加密流程:生成随机密钥→加密数据→存储加密后的数据和 IV(初始化向量)→解密时通过密钥和 IV 解密。

实现步骤

步骤 1:生成 AES 密钥并安全存储
import cryptoFramework from '@ohos.security.cryptoFramework';
import preferences from '@ohos.data.preferences';
import common from '@ohos.app.ability.common';

class AesEncryptionManager {
  private context = getContext(this) as common.UIAbilityContext;
  private keyAlias = 'aes_user_key'; // 密钥别名

  // 生成AES-256密钥并存储到KeyStore
  async generateAndSaveKey() {
    try {
      // 1. 创建密钥生成器(AES-256-GCM)
      const keyGenerator = cryptoFramework.createKeyGenerator('AES', 'software');
      const keySpec = {
        keySize: 256, // AES-256
        purpose: [cryptoFramework.KeyPurpose.ENCRYPT, cryptoFramework.KeyPurpose.DECRYPT]
      };
      await keyGenerator.init(keySpec);

      // 2. 生成密钥
      const key = await keyGenerator.generateKey();

      // 3. 存储密钥到KeyStore(安全存储,不可直接访问)
      const keyStore = cryptoFramework.getKeyStore('software');
      await keyStore.storeKey(this.keyAlias, key, {
        accessible: cryptoFramework.KeyAccessible.ALWAYS_AVAILABLE
      });
      console.log('AES密钥生成并存储成功');
    } catch (err) {
      console.error('密钥生成失败:', err);
    }
  }
}
步骤 2:AES 加密实现
// 加密数据(如密码)
async encryptData(plainText: string): Promise<string> {
  try {
    // 1. 获取存储的AES密钥
    const keyStore = cryptoFramework.getKeyStore('software');
    const key = await keyStore.getKey(this.keyAlias) as cryptoFramework.SymmetricKey;

    // 2. 生成随机IV(12字节,GCM模式推荐)
    const iv = cryptoFramework.generateRandomBytes(12);
    const ivBase64 = iv.toString('base64');

    // 3. 创建加密器
    const cipher = cryptoFramework.createCipher('AES-GCM', 'software');
    const encryptParams = {
      iv: iv,
      authTagLength: 16 // 认证标签长度
    };
    await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, key, encryptParams);

    // 4. 加密数据(UTF-8编码)
    const plainTextUint8 = new TextEncoder().encode(plainText);
    const encryptedData = await cipher.doFinal(plainTextUint8);
    const encryptedBase64 = encryptedData.toString('base64');

    // 5. 存储IV(解密需要,与加密数据一起存储)
    const pref = await preferences.getPreferences(this.context, 'secure_storage');
    await pref.putString(`${this.keyAlias}_iv`, ivBase64);
    await pref.flush();

    // 6. 返回加密后的数据(Base64编码,便于存储)
    return encryptedBase64;
  } catch (err) {
    console.error('加密失败:', err);
    throw err;
  }
}
步骤 3:AES 解密实现
// 解密数据
async decryptData(encryptedBase64: string): Promise<string> {
  try {
    // 1. 获取密钥和IV
    const keyStore = cryptoFramework.getKeyStore('software');
    const key = await keyStore.getKey(this.keyAlias) as cryptoFramework.SymmetricKey;
    
    const pref = await preferences.getPreferences(this.context, 'secure_storage');
    const ivBase64 = await pref.getString(`${this.keyAlias}_iv`, '');
    const iv = cryptoFramework.fromBase64(ivBase64);

    // 2. 创建解密器
    const cipher = cryptoFramework.createCipher('AES-GCM', 'software');
    const decryptParams = {
      iv: iv,
      authTagLength: 16
    };
    await cipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, key, decryptParams);

    // 3. 解密数据
    const encryptedUint8 = cryptoFramework.fromBase64(encryptedBase64);
    const decryptedUint8 = await cipher.doFinal(encryptedUint8);

    // 4. 解码为字符串
    return new TextDecoder().decode(decryptedUint8);
  } catch (err) {
    console.error('解密失败:', err);
    throw err;
  }
}
步骤 4:使用示例
// 初始化并加密密码
async useEncryption() {
  const aesManager = new AesEncryptionManager();
  // 首次使用时生成密钥(仅需生成一次)
  await aesManager.generateAndSaveKey();
  
  // 加密密码
  const password = '123456';
  const encryptedPwd = await aesManager.encryptData(password);
  console.log('加密后:', encryptedPwd);
  
  // 解密密码
  const decryptedPwd = await aesManager.decryptData(encryptedPwd);
  console.log('解密后:', decryptedPwd); // 输出123456
}

避坑提醒

  • AES 密钥必须存储在 KeyStore,不能硬编码或明文存储在 Preferences;
  • IV(初始化向量)需随机生成,且每次加密不同,解密时必须使用相同 IV;
  • 推荐使用 AES-256-GCM 模式,兼顾安全性和性能,避免使用 ECB 模式;
  • 敏感数据加密后,建议存储在preferencesRelationalStore,无需额外加密存储介质。

更多关于HarmonyOS鸿蒙Next中APP如何实现敏感数据(如密码)的AES加密存储?的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

在HarmonyOS Next中,使用安全子系统的Crypto Framework进行AES加密。通过cryptoFramework.createCipher创建AES-GCM或AES-CCM模式的Cipher实例。使用cryptoFramework.createSymKeyGenerator生成密钥,通过cryptoFramework.createCipher进行加密操作。敏感数据加密后,应使用用户认证框架保护的凭据管理API(@ohos.userIAM.userAuth)存储加密后的密钥或数据。

更多关于HarmonyOS鸿蒙Next中APP如何实现敏感数据(如密码)的AES加密存储?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


您的实现方案整体正确,核心思路和API使用得当。这里针对HarmonyOS Next的特性,补充几个关键点和优化建议:

  1. KeyStore类型选择:示例中使用的是 'software' 软件级KeyStore。对于更高安全要求的敏感数据(如支付相关),建议使用 'hardware' 硬件级KeyStore(如果设备支持),它能提供基于安全芯片的硬件级保护。

  2. 密钥生成时机generateAndSaveKey() 方法在每次调用时都会生成新密钥。在实际应用中,应先检查密钥是否已存在(通过 keyStore.getKey() 捕获异常或使用 keyStore.hasKey() 方法),避免重复生成导致旧数据无法解密。

  3. IV存储的完整性:当前方案将IV与加密数据分开存储。一个更严谨的做法是将IV和加密数据(及GCM的认证标签)作为一个整体存储,例如将 IV + encryptedData 拼接后再进行Base64编码存储,解密时按固定长度拆分。这能更好地保证数据关联性。

  4. 错误处理增强:在解密失败时(如IV被篡改或密钥不匹配),GCM模式会抛出异常。应确保异常被妥善捕获,并转化为统一的错误处理,避免向用户暴露密码学细节。

  5. API兼容性:确保在模块的 oh-package.json5 中已正确声明依赖:

    "dependencies": {
      "@ohos.security.cryptoFramework": ">= 12.0.0.0"
    }
    

您的代码清晰地展示了鸿蒙原生AES-GCM加密解密的完整流程,遵循了“密钥进KeyStore,数据加密存储”的安全最佳实践,可直接用于登录密码等敏感信息的本地保护。

回到顶部