import { createCipheriv, createDecipheriv, scryptSync, randomBytes } from "crypto"; import { ValueTransformer } from "typeorm"; export abstract class CodingHelper { private static readonly algorithm = "aes-256-gcm"; private static readonly ivLength = 16; private static readonly authTagLength = 16; static entityBaseCoding(key: string = "", fallback: string = ""): ValueTransformer { return { from(val: string | null | undefined): string { if (!val || val == "") return fallback; try { return CodingHelper.decrypt(key, val, true); } catch (error) { console.error("Decryption error:", error); if (fallback == "") return val; else return fallback; } }, to(val: string | null | undefined): string { const valueToEncrypt = val || fallback; if (valueToEncrypt === "") return ""; try { return CodingHelper.encrypt(key, valueToEncrypt, true); } catch (error) { console.error("Encryption error:", error); if (fallback == "") return val; return ""; } }, }; } public static encrypt(phrase: string, content: string, passError = false): string { if (!content) return ""; try { // Generiere zufälligen IV für jede Verschlüsselung (sicherer als statischer IV) const iv = randomBytes(this.ivLength); const key = scryptSync(phrase, "salt", 32); const cipher = createCipheriv(this.algorithm, Uint8Array.from(key), Uint8Array.from(iv)); // Verschlüssele den Inhalt let encrypted = cipher.update(content, "utf8", "hex"); encrypted += cipher.final("hex"); // Speichere das Auth-Tag für GCM (wichtig für die Entschlüsselung) const authTag = cipher.getAuthTag(); // Gib das Format: iv:verschlüsselter_text:authTag zurück return Buffer.concat([ Uint8Array.from(iv), Uint8Array.from(Buffer.from(encrypted, "hex")), Uint8Array.from(authTag), ]).toString("base64"); } catch (error) { if (passError) throw error; console.error("Encryption failed:", error); return ""; } } public static decrypt(phrase: string, content: string, passError = false): string { if (!content) return ""; try { // Dekodiere den Base64-String const buffer = Buffer.from(content, "base64"); // Extrahiere IV, verschlüsselten Text und Auth-Tag const iv = buffer.subarray(0, this.ivLength); const authTag = buffer.subarray(buffer.length - this.authTagLength); const encryptedText = buffer.subarray(this.ivLength, buffer.length - this.authTagLength).toString("hex"); const key = scryptSync(phrase, "salt", 32); // Erstelle Decipher und setze Auth-Tag const decipher = createDecipheriv(this.algorithm, Uint8Array.from(key), Uint8Array.from(iv)); decipher.setAuthTag(Uint8Array.from(authTag)); // Entschlüssele den Text let decrypted = decipher.update(encryptedText, "hex", "utf8"); decrypted += decipher.final("utf8"); return decrypted; } catch (error) { if (passError) throw error; console.error("Decryption failed:", error); return ""; } } }