import { createCipheriv, createDecipheriv, randomBytes } from "crypto"; const ALGORITHM = "aes-256-gcm"; const KEY_LENGTH = 32; function getKey(): Buffer { const raw = process.env.NUXT_ENCRYPTION_KEY || process.env.ENCRYPTION_KEY || ""; if (!raw || raw.length < 32) { // Fallback: pad with zeros (only for dev without key) return Buffer.alloc( KEY_LENGTH, raw.padEnd(KEY_LENGTH, "0").slice(0, KEY_LENGTH), ); } return Buffer.from(raw.slice(0, KEY_LENGTH), "utf8"); } export function encrypt(text: string): string { const key = getKey(); const iv = randomBytes(12); const cipher = createCipheriv(ALGORITHM, key, iv); const encrypted = Buffer.concat([ cipher.update(text, "utf8"), cipher.final(), ]); const tag = cipher.getAuthTag(); // Format: iv(24hex):tag(32hex):encrypted(hex) return `${iv.toString("hex")}:${tag.toString("hex")}:${encrypted.toString("hex")}`; } export function decrypt(stored: string): string { const key = getKey(); const parts = stored.split(":"); if (parts.length !== 3) throw new Error("Invalid encrypted format"); const [ivHex, tagHex, dataHex] = parts; const iv = Buffer.from(ivHex, "hex"); const tag = Buffer.from(tagHex, "hex"); const data = Buffer.from(dataHex, "hex"); const decipher = createDecipheriv(ALGORITHM, key, iv); decipher.setAuthTag(tag); return decipher.update(data) + decipher.final("utf8"); }