数据库加密:HarmonyOS开发安全存储实践
📌 核心要点:数据库加密是应用安全的重要防线,HarmonyOS通过RDB加密和HUKS密钥管理,实现透明且安全的数据存储
一、背景与动机
数据泄露的新闻你肯定没少见——某某App用户数据泄露、某某公司数据库被拖库……这些事故背后,往往都有一个共同原因:敏感数据明文存储。
你想想,用户手机丢了,或者被恶意软件读取数据目录,如果你的数据库里存着用户的支付密码、聊天记录、身份证号,而且全是明文,那后果简直不敢想。这就是为什么数据库加密不是"锦上添花",而是"必备技能"。
HarmonyOS在这方面做得挺到位——RDB数据库原生支持加密,而且跟HUKS(HarmonyOS Universal Key Store)深度集成。说白了,你不用自己操心密钥怎么存、怎么防窃取,系统帮你搞定一切。加密过程对应用透明,该CRUD还是CRUD,完全感知不到加密的存在。
二、核心原理
2.1 加密架构
HarmonyOS数据库加密采用分层架构:
2.2 加密流程
当创建加密数据库时,系统会自动完成以下步骤:
- 密钥生成:调用HUKS生成AES-256密钥
- 密钥派生:基于用户密码派生数据库加密密钥
- 数据库初始化:SQLite层设置加密参数
- 透明加密:写入时自动加密,读取时自动解密
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 新增特性
- 硬件加密加速:利用TEE加速加密运算,性能提升40%+
- 多密钥支持:同一数据库支持多个加密密钥,不同表可用不同密钥
- 密钥轮换:支持在线密钥轮换,无需停机
- 审计日志:加密操作自动记录审计日志
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
};六、总结
| 维度 | 评价 |
|---|---|
| 学习难度 | ⭐⭐⭐⭐ |
| 使用频率 | ⭐⭐⭐ |
| 重要程度 | ⭐⭐⭐⭐⭐ |
| 调试难度 | ⭐⭐⭐⭐ |
核心收获:
- 数据库加密是应用安全的底线,涉及敏感数据必须加密,这是原则问题
- HUKS是密钥管理的正确姿势,利用硬件级安全保护,避免密钥泄露
- 透明加密让开发无感知,加密后的数据库使用方式完全不变
- 密钥管理比加密算法更重要,密钥泄露了,再强的加密也没用
- HarmonyOS 6的硬件加速是重大利好,性能不再是加密的借口
下一步建议:
- 学习HUKS的高级特性:密钥协商、签名验签
- 研究分布式场景下的密钥同步问题
- 探索端到端加密在即时通讯中的应用
- 实现密钥托管和恢复机制
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。