mirror of
https://github.com/CompassConnections/Compass.git
synced 2026-01-19 11:18:33 -05:00
58 lines
2.1 KiB
TypeScript
58 lines
2.1 KiB
TypeScript
import crypto from "crypto";
|
|
import {ENV_CONFIG} from "common/envs/constants";
|
|
|
|
/**
|
|
* MASTER_KEY must be a 32-byte Buffer (AES-256).
|
|
* Load it from a secrets manager at runtime; do NOT hardcode.
|
|
*/
|
|
let _MASTER_KEY: Buffer | null = null
|
|
const getMasterKey = () => {
|
|
if (_MASTER_KEY) return _MASTER_KEY
|
|
|
|
if (ENV_CONFIG.dbEncryptionKey) {
|
|
const MASTER_KEY_BASE64 = ENV_CONFIG.dbEncryptionKey
|
|
_MASTER_KEY = Buffer.from(MASTER_KEY_BASE64, "base64")
|
|
if (_MASTER_KEY.length !== 32) throw new Error("MASTER_KEY must be 32 bytes")
|
|
}
|
|
|
|
if (!_MASTER_KEY) throw new Error("MASTER_KEY not set")
|
|
|
|
return _MASTER_KEY
|
|
}
|
|
|
|
/**
|
|
* Encrypt a UTF-8 message string into base64 ciphertext + iv + tag.
|
|
* The IV makes the encryption probabilistic to ensure uniqueness in ciphertexts even when encrypting the same plaintext
|
|
* multiple times and has therefore no intent of being secret. The authentication tag works similar to a MAC.
|
|
* It's used to prove the authenticity and integrity of a message
|
|
*/
|
|
export function encryptMessage(plaintext: string) {
|
|
const iv = crypto.randomBytes(12); // 96-bit IV, recommended for AES-GCM
|
|
const cipher = crypto.createCipheriv("aes-256-gcm", getMasterKey(), iv);
|
|
const ciphertext = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
|
|
const tag = cipher.getAuthTag();
|
|
|
|
// console.debug(plaintext, iv, ciphertext, tag)
|
|
|
|
return {
|
|
ciphertext: ciphertext.toString("base64"),
|
|
iv: iv.toString("base64"),
|
|
tag: tag.toString("base64"),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Decrypt base64 ciphertext + iv + tag -> plaintext string.
|
|
* Throws on auth failure.
|
|
*/
|
|
export function decryptMessage({ciphertext, iv, tag}: { ciphertext: string; iv: string; tag: string; }) {
|
|
const ivBuf = Buffer.from(iv, "base64");
|
|
const ctBuf = Buffer.from(ciphertext, "base64");
|
|
const tagBuf = Buffer.from(tag, "base64");
|
|
|
|
const decipher = crypto.createDecipheriv("aes-256-gcm", getMasterKey(), ivBuf);
|
|
decipher.setAuthTag(tagBuf);
|
|
const plaintext = Buffer.concat([decipher.update(ctBuf), decipher.final()]).toString("utf8");
|
|
// console.debug("Decrypted message:", plaintext);
|
|
return plaintext;
|
|
} |