import { base64Decode, base64Encode, } from "../../plugos/asset_bundle/base64.ts"; const encoder = new TextEncoder(); const decoder = new TextDecoder(); export async function deriveKeyFromPassword( password: string, salt: string, ): Promise { const baseKey = encoder.encode(password); const importedKey = await window.crypto.subtle.importKey( "raw", baseKey, { name: "PBKDF2" }, false, ["deriveKey"], ); return crypto.subtle.deriveKey( { name: "PBKDF2", salt: encoder.encode(salt), iterations: 10000, hash: "SHA-256", }, importedKey, { name: "AES-GCM", length: 256, }, true, ["encrypt", "decrypt"], ); } export async function encryptAES( key: CryptoKey, message: string, ): Promise { const iv = crypto.getRandomValues(new Uint8Array(12)); const encodedMessage = encoder.encode(message); const ciphertext = await window.crypto.subtle.encrypt( { name: "AES-GCM", iv: iv, }, key, encodedMessage, ); return appendBuffer(iv, ciphertext); } export async function decryptAES( key: CryptoKey, data: ArrayBuffer, ): Promise { const iv = data.slice(0, 12); const ciphertext = data.slice(12); const decrypted = await window.crypto.subtle.decrypt( { name: "AES-GCM", iv: iv, }, key, ciphertext, ); return decoder.decode(decrypted); } function appendBuffer(buffer1: ArrayBuffer, buffer2: ArrayBuffer): ArrayBuffer { const tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength); tmp.set(new Uint8Array(buffer1), 0); tmp.set(new Uint8Array(buffer2), buffer1.byteLength); return tmp.buffer; } // This is against security recommendations, but we need a way to always generate the same encrypted path for the same path and password const pathIv = new Uint8Array(12); // 12 bytes of 0 export async function encryptPath( key: CryptoKey, path: string, ): Promise { const encodedMessage = encoder.encode(path); const ciphertext = await crypto.subtle.encrypt( { name: "AES-GCM", iv: pathIv, }, key, encodedMessage, ); return base64Encode(new Uint8Array(ciphertext)); } export async function decryptPath( key: CryptoKey, data: string, ): Promise { const decrypted = await crypto.subtle.decrypt( { name: "AES-GCM", iv: pathIv, }, key, base64Decode(data), ); return decoder.decode(decrypted); }