/** * Simple encryption utilities for storing sensitive data * Uses Web Crypto API for encryption/decryption */ // Get or generate encryption key // In production, this should be stored securely (e.g., environment variable) // For now, we'll use a derivation from a fixed string + user context const getEncryptionKey = async (): Promise => { const keyMaterial = await crypto.subtle.importKey( "raw", new TextEncoder().encode( // In production, use a secure environment variable import.meta.env.VITE_ENCRYPTION_KEY || "atomic-crm-default-key-change-in-production" ), "PBKDF2", false, ["deriveBits", "deriveKey"] ); return crypto.subtle.deriveKey( { name: "PBKDF2", salt: new TextEncoder().encode("atomic-crm-salt"), iterations: 100000, hash: "SHA-256", }, keyMaterial, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"] ); }; /** * Encrypt a string value */ export const encryptValue = async (value: string): Promise => { const key = await getEncryptionKey(); const iv = crypto.getRandomValues(new Uint8Array(12)); const encoded = new TextEncoder().encode(value); const encrypted = await crypto.subtle.encrypt( { name: "AES-GCM", iv }, key, encoded ); // Combine IV and encrypted data const combined = new Uint8Array(iv.length + encrypted.byteLength); combined.set(iv); combined.set(new Uint8Array(encrypted), iv.length); // Convert to base64 return btoa(String.fromCharCode(...combined)); }; /** * Decrypt an encrypted string value */ export const decryptValue = async (encryptedValue: string): Promise => { const key = await getEncryptionKey(); // Decode from base64 const combined = Uint8Array.from(atob(encryptedValue), (c) => c.charCodeAt(0)); // Extract IV and encrypted data const iv = combined.slice(0, 12); const encrypted = combined.slice(12); const decrypted = await crypto.subtle.decrypt( { name: "AES-GCM", iv }, key, encrypted ); return new TextDecoder().decode(decrypted); };