const getKeyFromPassword = async function (password) { const enc = new TextEncoder(); const keyMaterial = await crypto.subtle.importKey( "raw", enc.encode(password), "PBKDF2", false, ["deriveKey"] ); return crypto.subtle.deriveKey( { name: "PBKDF2", salt: new TextEncoder().encode("fixed-salt"), iterations: 100000, hash: "SHA-256", }, keyMaterial, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"] ); }; const encrypt = async function (text, password) { const key = await getKeyFromPassword(password); const enc = new TextEncoder(); const iv = crypto.getRandomValues(new Uint8Array(12)); const ciphertext = await crypto.subtle.encrypt( { name: "AES-GCM", iv }, key, enc.encode(text) ); const buffer = new Uint8Array(iv.byteLength + ciphertext.byteLength); buffer.set(iv, 0); buffer.set(new Uint8Array(ciphertext), iv.byteLength); return btoa(String.fromCharCode(...buffer)); }; const decrypt = async function (encrypted, password) { const data = Uint8Array.from(atob(encrypted), c => c.charCodeAt(0)); const iv = data.slice(0, 12); const ciphertext = data.slice(12); const key = await getKeyFromPassword(password); const decrypted = await crypto.subtle.decrypt( { name: "AES-GCM", iv }, key, ciphertext ); return new TextDecoder().decode(decrypted); };