前言WebCrypto API 提供原生的加密能力。本文通过 AES-GCM 与口令派生实现文件加密,并演示密钥的安全持久化与加载流程。能力检测const supportsWebCrypto = !!(crypto && crypto.subtle);
口令派生与生成密钥async function deriveAesKeyFromPassphrase(passphrase, salt) {
const enc = new TextEncoder();
const baseKey = await crypto.subtle.importKey('raw', enc.encode(passphrase), 'PBKDF2', false, ['deriveKey']);
const key = await crypto.subtle.deriveKey({ name: 'PBKDF2', hash: 'SHA-256', salt: enc.encode(salt), iterations: 100000 }, baseKey, { name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt']);
return key;
}
async function generateAesKey() {
return crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt']);
}
加密与解密async function encryptBytes(key, bytes) {
const iv = crypto.getRandomValues(new Uint8Array(12));
const buf = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, bytes);
return { iv, cipher: new Uint8Array(buf) };
}
async function decryptBytes(key, iv, cipher) {
const buf = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, cipher);
return new Uint8Array(buf);
}
密钥导出与持久化async function exportRawKey(key) {
const raw = await crypto.subtle.exportKey('raw', key);
return new Uint8Array(raw);
}
async function importRawKey(raw) {
return crypto.subtle.importKey('raw', raw, { name: 'AES-GCM' }, true, ['encrypt', 'decrypt']);
}
将密钥与元数据写入 IndexedDB:function openDB(name) {
return new Promise((resolve, reject) => {
const req = indexedDB.open(name, 1);
req.onupgradeneeded = () => {
const db = req.result;
if (!db.objectStoreNames.contains('keys')) db.createObjectStore('keys', { keyPath: 'id' });
};
req.onsuccess = () => resolve(req.result);
req.onerror = () => reject(req.error);
});
}
async function saveKey(id, raw) {
const db = await openDB('crypto');
const tx = db.transaction('keys', 'readwrite');
tx.objectStore('keys').put({ id, raw });
await new Promise((resolve, reject) => { tx.oncomplete = resolve; tx.onerror = () => reject(tx.error); });
db.close();
}
async function loadKey(id) {
const db = await openDB('crypto');
const tx = db.transaction('keys', 'readonly');
const req = tx.objectStore('keys').get(id);
const rec = await new Promise((resolve, reject) => { req.onsuccess = () => resolve(req.result); req.onerror = () => reject(req.error); });
db.close();
return rec ? importRawKey(new Uint8Array(rec.raw)) : null;
}

发表评论 取消回复