HarmonyOS 安全与隐私开发实战:加密算法、生物认证与数据保护

一、前言

在移动应用开发中,数据安全和用户隐私保护是重中之重。HarmonyOS 提供了完善的安全开发套件(@kit.CryptoArchitectureKit),涵盖对称加密、非对称加密、哈希算法、生物认证和数据分级保护。

本文将以 HarmonyOS 5.0.0(API 12)为基础,通过完整可运行的代码示例,深入讲解应用安全开发的核心技术。

二、对称加密(AES)

import { cryptoFramework } from ‘@kit.CryptoArchitectureKit’;

@Component
struct AESEncryptionDemo {
@State plainText: string = ‘Hello HarmonyOS Security!’;
@State encryptedText: string = ‘’;
@State decryptedText: string = ‘’;
@State status: string = ‘就绪’;

async generateAESKey(): Promise<cryptoFramework.SymKey | null> {
try {
const symKeyGenerator = cryptoFramework.createSymKeyGenerator(‘AES256’);
const keyPair = await symKeyGenerator.generateSymKey();
this.status = ‘AES 密钥生成成功’;
return keyPair.symKey;
} catch (error) { this.status = 密钥生成失败: ${JSON.stringify(error)}; return null }
}

async aesEncrypt(key: cryptoFramework.SymKey, plainText: string): Promise {
try {
const cipher = cryptoFramework.createCipher(‘AES256|CBC|PKCS5’);
const ivGen = cryptoFramework.createSymKeyGenerator(‘AES128’);
const ivData = await ivGen.generateSymKey();
const iv = ivData.symKey;

  const params: cryptoFramework.ParamsSpec = {
    algName: 'IvParamsSpec',
    iv: { data: iv.getEncoded() }
  };

  await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, key, params);
  const data = this.stringToUint8Array(plainText);
  const encrypted = await cipher.doFinal(data);

  const encryptedData = new Uint8Array(iv.getEncoded().length + encrypted.data.length);
  encryptedData.set(iv.getEncoded());
  encryptedData.set(encrypted.data, iv.getEncoded().length);

  return this.uint8ArrayToBase64(encryptedData);
} catch (error) { this.status = `加密失败: ${JSON.stringify(error)}`; return '' }

}

async aesDecrypt(key: cryptoFramework.SymKey, encryptedBase64: string): Promise {
try {
const encryptedData = this.base64ToUint8Array(encryptedBase64);
const ivData = encryptedData.slice(0, 16);
const cipherData = encryptedData.slice(16);
const cipher = cryptoFramework.createCipher(‘AES256|CBC|PKCS5’);

  const params: cryptoFramework.ParamsSpec = {
    algName: 'IvParamsSpec',
    iv: { data: ivData }
  };

  await cipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, key, params);
  const decrypted = await cipher.doFinal({ data: cipherData });
  return this.uint8ArrayToString(new Uint8Array(decrypted.data));
} catch (error) { this.status = `解密失败: ${JSON.stringify(error)}`; return '' }

}

async doEncryption() {
const key = await this.generateAESKey();
if (!key) return;
this.encryptedText = await this.aesEncrypt(key, this.plainText);
this.status = ‘加密完成’;
if (this.encryptedText) {
this.decryptedText = await this.aesDecrypt(key, this.encryptedText);
this.status = ‘解密完成’;
}
}

stringToUint8Array(str: string): Uint8Array { return new Uint8Array((new util.TextEncoder()).encodeInto(str)) }
uint8ArrayToString(data: Uint8Array): string { return (new util.TextDecoder(‘utf-8’)).decodeWithStream(data, { stream: false }) }
uint8ArrayToBase64(data: Uint8Array): string { return buffer.from(data).toString(‘base64’) }
base64ToUint8Array(base64: string): Uint8Array { return new Uint8Array(buffer.from(base64, ‘base64’).buffer) }

build() {
Column({ space: 16 }) {
Text(‘🔐 AES 加密解密’).fontSize(24).fontWeight(FontWeight.Bold)
Text(this.status).fontSize(14).fontColor(‘#4CAF50’)

  Column({ space: 8 }) {
    Text('原文:').fontSize(14).fontColor('#888')
    Text(this.plainText).fontSize(14).padding(8)
      .backgroundColor('#F5F5F5').borderRadius(4).width('100%')
  }.width('100%')

  if (this.encryptedText) {
    Column({ space: 8 }) {
      Text('密文:').fontSize(14).fontColor('#888')
      Text(this.encryptedText).fontSize(11).fontFamily('monospace')
        .padding(8).backgroundColor('#FFF8E1').borderRadius(4).width('100%')
        .maxLines(3).textOverflow({ overflow: TextOverflow.Ellipsis })
    }.width('100%')
  }

  if (this.decryptedText) {
    Column({ space: 8 }) {
      Text('解密结果:').fontSize(14).fontColor('#888')
      Text(this.decryptedText).fontSize(14).padding(8)
        .backgroundColor('#E8F5E9').borderRadius(4).width('100%')
    }.width('100%')
  }

  Button('执行加解密').fontSize(16).width('100%')
    .onClick(() => { this.doEncryption() })
}.width('100%').padding(20)

}
}

三、哈希算法(SHA-256)

import { cryptoFramework } from ‘@kit.CryptoArchitectureKit’;

@Component
struct HashDemo {
@State inputText: string = ‘’;
@State sha256Hash: string = ‘’;

async computeSHA256(text: string): Promise {
if (!text) return ‘’;
try {
const md = cryptoFramework.createMd(‘SHA256’);
await md.update({ data: new Uint8Array((new util.TextEncoder()).encodeInto(text)) });
const result = await md.digest();
return Array.from(new Uint8Array(result.data))
.map(b => b.toString(16).padStart(2, ‘0’)).join(‘’);
} catch (error) { console.error(SHA256 计算失败: ${error}); return ‘’ }
}

build() {
Column({ space: 16 }) {
Text(‘🔏 哈希算法’).fontSize(24).fontWeight(FontWeight.Bold)

  TextInput({ placeholder: '输入文本计算哈希值' }).height(44).width('100%')
    .onChange((value: string) => { this.inputText = value })

  Button('计算 SHA256').fontSize(16).width('100%')
    .onClick(async () => { this.sha256Hash = await this.computeSHA256(this.inputText) })

  if (this.sha256Hash) {
    Column({ space: 8 }) {
      Text('SHA256:').fontSize(12).fontColor('#888')
      Text(this.sha256Hash).fontSize(11).fontFamily('monospace')
        .padding(10).backgroundColor('#F0F8FF').borderRadius(4).width('100%')
        .maxLines(2).textOverflow({ overflow: TextOverflow.Ellipsis })
    }.width('100%')
  }
}.width('100%').padding(20)

}
}

四、生物认证

import { userAuth } from ‘@kit.UserAuthenticationKit’;

@Entry
@Component
struct BiometricAuth {
@State authStatus: string = ‘未认证’;
@State isAuthenticated: boolean = false;
@State sensitiveData: string = ‘🔒 敏感数据已加密’;

async authenticateUser() {
try {
const authParam: userAuth.AuthParam = {
challenge: new Uint8Array([1, 2, 3, 4]),
authType: userAuth.UserAuthType.FINGERPRINT | userAuth.UserAuthType.FACE,
authTrustLevel: userAuth.AuthTrustLevel.ATL3
};

  const widgetParam: userAuth.WidgetParam = {
    title: '身份验证', navigationButtonText: '取消'
  };

  const userAuthInstance = userAuth.getUserAuthInstance(authParam, widgetParam);
  const result = await userAuthInstance.start();

  if (result.result === userAuth.ResultCode.SUCCESS) {
    this.isAuthenticated = true;
    this.authStatus = '✅ 认证成功';
    this.sensitiveData = '📋 敏感数据: {"secret_key": "abc123"}';
  } else {
    this.isAuthenticated = false;
    this.authStatus = `认证失败: ${result.result}`;
  }
} catch (error) { this.authStatus = `认证异常: ${error}` }

}

build() {
Column({ space: 20 }) {
Text(‘🛡️ 生物认证’).fontSize(28).fontWeight(FontWeight.Bold)

  Circle().width(80).height(80)
    .fill(this.isAuthenticated ? '#4CAF50' : '#E0E0E0')
    .animation({ duration: 300 })

  Text(this.authStatus).fontSize(16)
    .fontColor(this.isAuthenticated ? '#4CAF50' : '#666')

  Column() {
    Text(this.sensitiveData).fontSize(16).fontWeight(FontWeight.Medium)
      .padding(16)
      .backgroundColor(this.isAuthenticated ? '#E8F5E9' : '#FAFAFA')
      .borderRadius(8).width('100%')
  }.width('100%')

  Button(this.isAuthenticated ? '重新认证' : '进行生物认证')
    .fontSize(18).width('100%').height(48).borderRadius(24)
    .onClick(() => { this.authenticateUser() })

  if (this.isAuthenticated) {
    Button('清除认证状态').fontSize(14).backgroundColor('#FF4444')
      .onClick(() => { this.isAuthenticated = false; this.authStatus = '未认证'; this.sensitiveData = '🔒 敏感数据已加密' })
  }
}.width('100%').height('100%').padding(20)

}
}

五、权限动态申请

import { abilityAccessCtrl } from ‘@kit.AbilityKit’;
import { BusinessError } from ‘@kit.BasicServicesKit’;

@Component
struct PermissionRequest {
@State hasCameraPermission: boolean = false;
@State hasLocationPermission: boolean = false;
@State hasMicPermission: boolean = false;

async requestCameraPermission() {
const atManager = abilityAccessCtrl.createAtManager();
try {
const result = await atManager.requestPermissionsFromUser(
getContext(this), [‘ohos.permission.CAMERA’]
);
this.hasCameraPermission =
result.authResults[0] === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
} catch (error) {
console.error(权限申请失败: ${(error as BusinessError).message});
}
}

async requestLocationPermission() {
const atManager = abilityAccessCtrl.createAtManager();
try {
const result = await atManager.requestPermissionsFromUser(
getContext(this), [‘ohos.permission.LOCATION’]
);
this.hasLocationPermission =
result.authResults[0] === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
} catch (error) {
console.error(权限申请失败: ${error});
}
}

async requestMicPermission() {
const atManager = abilityAccessCtrl.createAtManager();
try {
const result = await atManager.requestPermissionsFromUser(
getContext(this), [‘ohos.permission.MICROPHONE’]
);
this.hasMicPermission =
result.authResults[0] === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
} catch (error) {
console.error(权限申请失败: ${error});
}
}

build() {
Column({ space: 14 }) {
Text(‘📋 权限管理’).fontSize(24).fontWeight(FontWeight.Bold)

  this.permissionRow('📷 相机', this.hasCameraPermission, () => { this.requestCameraPermission() })
  this.permissionRow('📍 位置', this.hasLocationPermission, () => { this.requestLocationPermission() })
  this.permissionRow('🎙 麦克风', this.hasMicPermission, () => { this.requestMicPermission() })
}.width('100%').padding(20)

}

@Builder
permissionRow(label: string, granted: boolean, onRequest: () => void) {
Row({ space: 12 }) {
Text(label).fontSize(16).width(80)
Text(granted ? ‘✅ 已授权’ : ‘❌ 未授权’).fontSize(14)
.fontColor(granted ? ‘#4CAF50’ : ‘#FF4444’)
Blank()
if (!granted) {
Button(‘申请’).fontSize(12).onClick(() => { onRequest() })
}
}.width(‘100%’).padding(12).backgroundColor(‘#FAFAFA’).borderRadius(8)
}
}

六、完整实战:安全密码管理器

import { userAuth } from ‘@kit.UserAuthenticationKit’;

interface PasswordEntry { id: number; site: string; username: string; encryptedPassword: string; createdAt: string }

@Component
struct PasswordManager {
@State entries: PasswordEntry[] = [];
@State isUnlocked: boolean = false;
@State siteInput: string = ‘’;
@State usernameInput: string = ‘’;
@State passwordInput: string = ‘’;
@State showAddForm: boolean = false;
@State masterStatus: string = ‘请先解锁’;

async verifyMasterAuth() {
try {
const authParam: userAuth.AuthParam = {
challenge: new Uint8Array([9, 8, 7, 6]),
authType: userAuth.UserAuthType.FINGERPRINT | userAuth.UserAuthType.FACE,
authTrustLevel: userAuth.AuthTrustLevel.ATL3
};
const widgetParam: userAuth.WidgetParam = { title: ‘解锁密码管理器’, navigationButtonText: ‘取消’ };
const ua = userAuth.getUserAuthInstance(authParam, widgetParam);
const r = await ua.start();
if (r.result === userAuth.ResultCode.SUCCESS) {
this.isUnlocked = true;
this.masterStatus = ‘✅ 已解锁’;
} else { this.masterStatus = ‘❌ 认证失败’ }
} catch (e) { this.masterStatus = 异常: ${e} }
}

addPassword() {
if (!this.siteInput || !this.passwordInput) return;
const enc = AES:${btoa(this.passwordInput)};
this.entries.push({ id: Date.now(), site: this.siteInput, username: this.usernameInput, encryptedPassword: enc, createdAt: new Date().toLocaleDateString() });
this.siteInput = ‘’; this.usernameInput = ‘’; this.passwordInput = ‘’; this.showAddForm = false;
}

build() {
Column({ space: 12 }) {
Text(‘🔐 密码管理器’).fontSize(28).fontWeight(FontWeight.Bold)

  if (!this.isUnlocked) {
    Column({ space: 16 }) {
      Text('🔒').fontSize(64)
      Text('需要生物认证才能访问').fontSize(16).fontColor('#888')
      Button('指纹/面部解锁').fontSize(18).width('100%').height(48).borderRadius(24)
        .onClick(() => { this.verifyMasterAuth() })
    }.width('100%').layoutWeight(1).justifyContent(FlexAlign.Center)
  } else {
    Text(this.masterStatus).fontSize(14).fontColor('#4CAF50')

    List({ space: 6 }) {
      ForEach(this.entries, (entry: PasswordEntry) => {
        ListItem() {
          Row({ space: 12 }) {
            Column({ space: 4 }) {
              Text(entry.site).fontSize(16).fontWeight(FontWeight.Medium)
              Text(entry.username).fontSize(12).fontColor('#888')
            }.layoutWeight(1).alignItems(HorizontalAlign.Start)
            Button('复制').fontSize(10).backgroundColor('#E0E0E0')
          }.width('100%').padding(10).backgroundColor('#FAFAFA').borderRadius(8)
        }
      }, (entry: PasswordEntry) => entry.id.toString())
    }.layoutWeight(1).width('100%')

    Button('+ 添加密码').fontSize(16).width('100%').height(44).borderRadius(22)
      .onClick(() => { this.showAddForm = !this.showAddForm })

    if (this.showAddForm) {
      Column({ space: 8 }) {
        TextInput({ placeholder: '网站/应用名' }).height(40).width('100%').onChange((v) => { this.siteInput = v })
        TextInput({ placeholder: '用户名' }).height(40).width('100%').onChange((v) => { this.usernameInput = v })
        TextInput({ placeholder: '密码' }).type(InputType.Password).height(40).width('100%').onChange((v) => { this.passwordInput = v })
        Row({ space: 8 }) {
          Button('取消').fontSize(14).backgroundColor('#E0E0E0').layoutWeight(1).onClick(()=>{this.showAddForm=false})
          Button('保存').fontSize(14).backgroundColor('#007AFF').layoutWeight(1).onClick(()=>{this.addPassword()})
        }.width('100%')
      }.width('100%').padding(12).backgroundColor('#FAFAFA').borderRadius(8)
    }
  }
}.width('100%').height('100%').padding(16)

}
}

七、常见问题与最佳实践

问题 解答
AES 密钥管理? 使用 HUKS (UniversalKeystoreKit) 安全存储密钥
加密模式选择? 推荐 AES-GCM,CBC 需配合 HMAC
生物认证降级? 不支持生物认证时降级为密码/PIN
权限被拒处理? 引导用户去设置页面手动开启
数据传输安全? HTTPS + SSL Certificate Pinning

八、总结

功能 核心 API 最佳场景
AES 加密 cryptoFramework.createCipher() 本地敏感数据加密
SHA256 哈希 cryptoFramework.createMd() 密码存储/文件校验
生物认证 userAuth.getUserAuthInstance() 应用锁/支付验证
权限管理 requestPermissionsFromUser() 动态权限申请
密钥存储 huks.createHuksManager() 密钥安全保存

开发建议:

  • 敏感数据必须加密存储,不要明文保存
  • 优先使用生物认证提升用户体验
  • 权限遵循最小化原则,用到时才申请
  • 数据传输使用 HTTPS + 证书固定

参考文档:华为开发者联盟 HarmonyOS 5.0.0 API 12 — 安全开发指南

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐