ff-admin-server/src/helpers/codingHelper.ts

96 lines
3.2 KiB
TypeScript
Raw Normal View History

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 == "<self>") 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 == "<self>") 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 "";
}
}
}