Enhance encryption methods in admin configuration to use AES-256-GCM with key derivation
Build And Push Image / docker (push) Successful in 3m6s Details

This commit is contained in:
Matt 2025-08-07 20:23:18 +02:00
parent ce0cbdc980
commit d0d7a34ae7
1 changed files with 42 additions and 5 deletions

View File

@ -1,6 +1,6 @@
import { readFile, writeFile, mkdir, access, constants } from 'fs/promises'; import { readFile, writeFile, mkdir, access, constants } from 'fs/promises';
import { join } from 'path'; import { join } from 'path';
import { createCipher, createDecipher } from 'crypto'; import { createCipheriv, createDecipheriv, randomBytes, pbkdf2Sync } from 'crypto';
import type { NocoDBSettings } from '~/utils/types'; import type { NocoDBSettings } from '~/utils/types';
interface AdminConfiguration { interface AdminConfiguration {
@ -49,10 +49,23 @@ function encryptSensitiveData(data: string): string {
} }
try { try {
const cipher = createCipher('aes256', encryptionKey); // Use AES-256-GCM for modern encryption
const algorithm = 'aes-256-gcm';
const iv = randomBytes(16);
const salt = randomBytes(16);
// Derive key from the encryption key
const key = pbkdf2Sync(encryptionKey, salt, 100000, 32, 'sha256');
const cipher = createCipheriv(algorithm, key, iv);
let encrypted = cipher.update(data, 'utf8', 'hex'); let encrypted = cipher.update(data, 'utf8', 'hex');
encrypted += cipher.final('hex'); encrypted += cipher.final('hex');
return encrypted;
const authTag = cipher.getAuthTag();
// Combine salt, iv, authTag, and encrypted data
const combined = salt.toString('hex') + ':' + iv.toString('hex') + ':' + authTag.toString('hex') + ':' + encrypted;
return combined;
} catch (error) { } catch (error) {
console.error('[admin-config] Encryption failed:', error); console.error('[admin-config] Encryption failed:', error);
return data; return data;
@ -71,9 +84,33 @@ function decryptSensitiveData(encryptedData: string): string {
} }
try { try {
const decipher = createDecipher('aes256', encryptionKey); // Check if data contains our modern format with colons
let decrypted = decipher.update(encryptedData, 'hex', 'utf8'); if (!encryptedData.includes(':')) {
// Legacy data, return as-is
console.warn('[admin-config] Legacy encrypted data format detected, returning as-is');
return encryptedData;
}
const parts = encryptedData.split(':');
if (parts.length !== 4) {
throw new Error('Invalid encrypted data format');
}
const [saltHex, ivHex, authTagHex, encrypted] = parts;
const salt = Buffer.from(saltHex, 'hex');
const iv = Buffer.from(ivHex, 'hex');
const authTag = Buffer.from(authTagHex, 'hex');
// Derive key from the encryption key
const key = pbkdf2Sync(encryptionKey, salt, 100000, 32, 'sha256');
const algorithm = 'aes-256-gcm';
const decipher = createDecipheriv(algorithm, key, iv);
decipher.setAuthTag(authTag);
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8'); decrypted += decipher.final('utf8');
return decrypted; return decrypted;
} catch (error) { } catch (error) {
console.error('[admin-config] Decryption failed:', error); console.error('[admin-config] Decryption failed:', error);