import { Buffer } from "node:buffer"; const { crypto, crypto: { subtle } } = globalThis; export const sha256Hash = (value: string): Promise => subtle.digest("SHA-256", new TextEncoder().encode(value)); export const randomIV = (length: number): Uint8Array => crypto.getRandomValues(new Uint8Array(length)); export const importKey = async (password: string): Promise => { const key = await subtle.importKey( "raw", await sha256Hash(password), { name: "AES-GCM" }, false, ["encrypt", "decrypt"], ); return key; }; export const encryptText = async ( value: string, key: CryptoKey | string, ): Promise => { const theKey = key instanceof CryptoKey ? key : await importKey(key); const iv = randomIV(12); const decryptedValue = new TextEncoder().encode(value); const encryptedValue = await subtle.encrypt( { name: "AES-GCM", iv, }, theKey, decryptedValue, ); const ivBase64 = Buffer.from(iv).toString("base64"); const encryptedBase64 = Buffer.from(encryptedValue).toString("base64"); return `${ivBase64}:${encryptedBase64}`; }; export const decryptText = async ( value: string, key: CryptoKey | string, ): Promise => { const base64 = value.split(":"); const iv = Buffer.from(base64[0], "base64"); const encryptedValue = Buffer.from(base64[1], "base64"); const theKey = key instanceof CryptoKey ? key : await importKey(key); const decryptedValue = await subtle.decrypt( { name: "AES-GCM", iv, }, theKey, encryptedValue, ); return new TextDecoder().decode(decryptedValue); };