49 lines
1.7 KiB
TypeScript
49 lines
1.7 KiB
TypeScript
import crypto from "crypto";
|
|
|
|
const ALGORITHM = "aes-256-gcm";
|
|
|
|
function getKey() {
|
|
const env = process.env.CALDAV_ENCRYPTION_KEY;
|
|
if (!env || env.length < 32) {
|
|
throw new Error("CALDAV_ENCRYPTION_KEY muss mindestens 32 Zeichen lang sein");
|
|
}
|
|
return Buffer.from(env.slice(0, 32));
|
|
}
|
|
|
|
function encryptWithKey(value: string, key: Buffer): string {
|
|
const iv = crypto.randomBytes(16);
|
|
const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
|
|
const encrypted = Buffer.concat([cipher.update(value, "utf8"), cipher.final()]);
|
|
const authTag = cipher.getAuthTag();
|
|
return `${iv.toString("hex")}:${authTag.toString("hex")}:${encrypted.toString("hex")}`;
|
|
}
|
|
|
|
function decryptWithKey(value: string, key: Buffer): string {
|
|
const [ivHex, tagHex, encryptedHex] = value.split(":");
|
|
if (!ivHex || !tagHex || !encryptedHex) {
|
|
throw new Error("Ungültiges Secret-Format");
|
|
}
|
|
const decipher = crypto.createDecipheriv(ALGORITHM, key, Buffer.from(ivHex, "hex"));
|
|
decipher.setAuthTag(Buffer.from(tagHex, "hex"));
|
|
const decrypted = Buffer.concat([
|
|
decipher.update(Buffer.from(encryptedHex, "hex")),
|
|
decipher.final()
|
|
]);
|
|
return decrypted.toString("utf8");
|
|
}
|
|
|
|
export function encryptSecret(value: string): string {
|
|
return encryptWithKey(value, getKey());
|
|
}
|
|
|
|
export function decryptSecret(value: string): string {
|
|
return decryptWithKey(value, getKey());
|
|
}
|
|
|
|
export function reEncryptWithNewKey(encrypted: string, oldKeyHex: string): string {
|
|
if (!encrypted || !oldKeyHex || oldKeyHex.length < 32) return encrypted;
|
|
const oldKey = Buffer.from(oldKeyHex.slice(0, 32));
|
|
const plaintext = decryptWithKey(encrypted, oldKey);
|
|
return encryptWithKey(plaintext, getKey());
|
|
}
|