我想定期更新加密密钥,避免长期使用同一把。所以我应该如何使用 PBKDF2 之类的方式派生新密钥啊?求个思路。

鸿蒙官网鸿蒙应用开发
我想定期更新加密密钥,避免长期使用同一把。所以我应该如何使用 PBKDF2 之类的方式派生新密钥啊?求个思路。
相关代码如下:
```ts
const key = await crypto.subtle.deriveKey(
{ name:'PBKDF2', salt, iterations:10000, hash:'SHA-256' },
baseKey, { name:'AES-GCM', length:256 }, true, ['encrypt','decrypt']
);
```
您需要先 登录 才能评论/回答

全部评论(1)
import { crypto } from '@ohos.crypto';
import { util } from '@ohos.util';
// 密钥管理类
class KeyManager {
private static readonly PBKDF2_ITERATIONS = 100000;
private static readonly SALT_LENGTH = 16; // 128位盐值
private static readonly KEY_LENGTH = 256; // AES-256密钥长度
// 存储密钥版本和盐值的数据结构
private keyVersion: number = 1;
private keySalts: Map<number, Uint8Array> = new Map();
constructor() {
// 初始化时生成第一个盐值
this.generateNewSalt(this.keyVersion);
}
// 生成随机盐值
private generateNewSalt(version: number): void {
const salt = new Uint8Array(KeyManager.SALT_LENGTH);
crypto.getRandomValues(salt);
this.keySalts.set(version, salt);
}
// 使用PBKDF2派生密钥
async deriveKey(
password: ArrayBuffer,
version: number = this.keyVersion
): Promise<crypto.CryptoKey> {
// 获取对应版本的盐值
const salt = this.keySalts.get(version);
if (!salt) {
throw new Error(`No salt found for key version ${version}`);
}
try {
// 导入密码作为基础密钥材料
const baseKey = await crypto.subtle.importKey(
'raw',
password,
{ name: 'PBKDF2' },
false,
['deriveKey']
);
// 使用PBKDF2派生密钥
const key = await crypto.subtle.deriveKey(
{
name: 'PBKDF2',
salt: salt,
iterations: KeyManager.PBKDF2_ITERATIONS,
hash: 'SHA-256'
},
baseKey,
{ name: 'AES-GCM', length: KeyManager.KEY_LENGTH },
true,
['encrypt', 'decrypt']
);
return key;
} catch (error) {
console.error('Key derivation failed:', error);
throw error;
}
}
// 定期更新密钥
async rotateKey(password: ArrayBuffer): Promise<number> {
// 增加密钥版本
this.keyVersion++;
// 为新版本生成盐值
this.generateNewSalt(this.keyVersion);
// 派生新密钥
await this.deriveKey(password, this.keyVersion);
console.log(`Key rotated to version ${this.keyVersion}`);
return this.keyVersion;
}
// 获取当前密钥版本
getCurrentVersion(): number {
return this.keyVersion;
}
// 获取所有密钥版本信息(用于迁移旧数据)
getKeyVersions(): number[] {
return Array.from(this.keySalts.keys());
}
// 安全地清除旧密钥版本
purgeOldVersions(keepLastN: number = 2): void {
const versions = this.getKeyVersions().sort((a, b) => a - b);
const versionsToRemove = versions.slice(0, versions.length - keepLastN);
for (const version of versionsToRemove) {
this.keySalts.delete(version);
console.log(`Purged key version ${version}`);
}
}
// 序列化密钥元数据(用于持久化存储)
serializeMetadata(): string {
const metadata: {[version: string]: string} = {};
for (const [version, salt] of this.keySalts.entries()) {
// 将盐值转换为Base64以便存储
metadata[version.toString()] = util.base64Encode(salt);
}
return JSON.stringify({
currentVersion: this.keyVersion,
salts: metadata
});
}
// 从序列化数据恢复密钥元数据
deserializeMetadata(serialized: string): void {
const data = JSON.parse(serialized);
this.keyVersion = data.currentVersion;
this.keySalts.clear();
for (const [version, saltBase64] of Object.entries(data.salts)) {
const versionNum = parseInt(version, 10);
const salt = util.base64Decode(saltBase64 as string);
this.keySalts.set(versionNum, salt);
}
}
}
// 加密服务类
class EncryptionService {
private keyManager: KeyManager;
private currentKey: crypto.CryptoKey | null = null;
constructor() {
this.keyManager = new KeyManager();
}
// 初始化加密服务
async initialize(password: ArrayBuffer): Promise<void> {
this.currentKey = await this.keyManager.deriveKey(password);
}
// 加密数据(包含密钥版本信息)
async encryptData(data: ArrayBuffer): Promise<{ciphertext: ArrayBuffer, iv: Uint8Array, keyVersion: number}> {
if (!this.currentKey) {
throw new Error('Encryption service not initialized');
}
// 生成随机初始化向量
const iv = new Uint8Array(12); // 96位IV用于AES-GCM
crypto.getRandomValues(iv);
// 加密数据
const ciphertext = await crypto.subtle.encrypt(
{
name: 'AES-GCM',
iv: iv
},
this.currentKey,
data
);
return {
ciphertext,
iv,
keyVersion: this.keyManager.getCurrentVersion()
};
}
// 解密数据(自动处理密钥版本)
async decryptData(
ciphertext: ArrayBuffer,
iv: Uint8Array,
keyVersion: number,
password: ArrayBuffer
): Promise<ArrayBuffer> {
// 如果请求的密钥版本不是当前版本,先派生对应版本的密钥
let key: crypto.CryptoKey;
if (keyVersion === this.keyManager.getCurrentVersion()) {
key = this.currentKey!;
} else {
key = await this.keyManager.deriveKey(password, keyVersion);
}
// 解密数据
try {
const decrypted = await crypto.subtle.decrypt(
{
name: 'AES-GCM',
iv: iv
},
key,
ciphertext
);
return decrypted;
} catch (error) {
console.error('Decryption failed:', error);
throw new Error('Failed to decrypt data');
}
}
// 定期轮换密钥
async rotateKey(password: ArrayBuffer): Promise<void> {
const newVersion = await this.keyManager.rotateKey(password);
this.currentKey = await this.keyManager.deriveKey(password, newVersion);
}
// 数据迁移:使用新密钥重新加密所有数据
async migrateData(
oldPassword: ArrayBuffer,
encryptedData: Array<{ciphertext: ArrayBuffer, iv: Uint8Array, keyVersion: number}>
): Promise<Array<{ciphertext: ArrayBuffer, iv: Uint8Array, keyVersion: number}>> {
const migratedData = [];
for (const item of encryptedData) {
// 解密使用旧密钥加密的数据
const decrypted = await this.decryptData(
item.ciphertext,
item.iv,
item.keyVersion,
oldPassword
);
// 使用新密钥重新加密
const reencrypted = await this.encryptData(decrypted);
migratedData.push(reencrypted);
}
return migratedData;
}
}
// 使用示例
async function demonstrateKeyRotation() {
// 创建加密服务实例
const encryptionService = new EncryptionService();
// 假设用户提供的密码
const password = new TextEncoder().encode('user-secret-password');
// 初始化加密服务
await encryptionService.initialize(password);
// 加密一些数据
const originalData = new TextEncoder().encode('Sensitive data that needs protection');
const encrypted = await encryptionService.encryptData(originalData);
console.log(`Encrypted with key version: ${encrypted.keyVersion}`);
// 解密数据
const decrypted = await encryptionService.decryptData(
encrypted.ciphertext,
encrypted.iv,
encrypted.keyVersion,
password
);
console.log('Decrypted data:', new TextDecoder().decode(decrypted));
// 模拟定期密钥轮换
console.log('Rotating encryption key...');
await encryptionService.rotateKey(password);
// 使用新密钥加密数据
const newData = new TextEncoder().encode('New data encrypted with rotated key');
const newEncrypted = await encryptionService.encryptData(newData);
console.log(`Encrypted with new key version: ${newEncrypted.keyVersion}`);
// 解密使用新密钥加密的数据
const newDecrypted = await encryptionService.decryptData(
newEncrypted.ciphertext,
newEncrypted.iv,
newEncrypted.keyVersion,
password
);
console.log('Decrypted new data:', new TextDecoder().decode(newDecrypted));
// 验证旧密钥加密的数据仍然可解密
const oldDecrypted = await encryptionService.decryptData(
encrypted.ciphertext,
encrypted.iv,
encrypted.keyVersion,
password
);
console.log('Decrypted old data:', new TextDecoder().decode(oldDecrypted));
}
// 执行示例
demonstrateKeyRotation().catch(console.error);
📋 实现说明
1. 密钥派生过程
PBKDF2 (Password-Based Key Derivation Function 2) 通过以下步骤派生密钥:
输入密码:用户提供的密码作为基础密钥材料
添加盐值:随机生成的盐值确保即使相同密码也会产生不同密钥
多次哈希迭代:增加计算成本,防止暴力破解
生成最终密钥:派生出的密钥用于加密操作
2. 密钥轮换策略
版本控制:每个密钥版本关联唯一的盐值
向后兼容:保留旧密钥版本以便解密历史数据
定期更新:根据安全策略定期生成新密钥版本
安全清理:适时清除过于陈旧的密钥版本
3. 数据加密格式
建议的加密数据格式包含:
密文:实际加密后的数据
初始化向量(IV):随机值,确保相同明文产生不同密文
密钥版本:标识加密时使用的密钥版本

2025-09-12 13:19:37