RealBlocks / server /src /services /encryption.ts
incognitolm's picture
Initial
ce2d6ca verified
Raw
History Blame Contribute Delete
1.79 kB
import crypto from 'crypto';
import { config } from '../config';
const ALGORITHM = 'aes-256-gcm';
const IV_LENGTH = 16;
const TAG_LENGTH = 16;
function getKey(): Buffer {
const key = config.encryptionKey;
if (!key || key.length < 32) {
throw new Error('ENCRYPTION_KEY must be at least 32 characters long');
}
return Buffer.from(key.padEnd(32, 'x').slice(0, 32), 'utf8');
}
export function encrypt(text: string): { encrypted: string; iv: string; tag: string } {
const key = getKey();
const iv = crypto.randomBytes(IV_LENGTH);
const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
const tag = cipher.getAuthTag().toString('hex');
return {
encrypted,
iv: iv.toString('hex'),
tag,
};
}
export function encryptCombined(text: string): string {
const result = encrypt(text);
return `${result.encrypted}:${result.iv}:${result.tag}`;
}
export function decryptCombined(stored: string): string {
const parts = stored.split(':');
if (parts.length < 3) throw new Error('Invalid encrypted data format');
const tag = parts.pop()!;
const iv = parts.pop()!;
const encrypted = parts.join(':');
return decrypt(encrypted, iv, tag);
}
export function decrypt(encrypted: string, ivHex: string, tagHex: string): string {
const key = getKey();
const iv = Buffer.from(ivHex, 'hex');
const tag = Buffer.from(tagHex, 'hex');
const decipher = crypto.createDecipheriv(ALGORITHM, key, iv);
decipher.setAuthTag(tag);
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
export function hashToken(token: string): string {
return crypto.createHash('sha256').update(token).digest('hex');
}