前言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; }

发表评论 取消回复