From d0d7a34ae7d9f1a679849addbaa712a4a2db9303 Mon Sep 17 00:00:00 2001 From: Matt Date: Thu, 7 Aug 2025 20:23:18 +0200 Subject: [PATCH] Enhance encryption methods in admin configuration to use AES-256-GCM with key derivation --- server/utils/admin-config.ts | 47 ++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/server/utils/admin-config.ts b/server/utils/admin-config.ts index 3ac68ff..1366b6d 100644 --- a/server/utils/admin-config.ts +++ b/server/utils/admin-config.ts @@ -1,6 +1,6 @@ import { readFile, writeFile, mkdir, access, constants } from 'fs/promises'; import { join } from 'path'; -import { createCipher, createDecipher } from 'crypto'; +import { createCipheriv, createDecipheriv, randomBytes, pbkdf2Sync } from 'crypto'; import type { NocoDBSettings } from '~/utils/types'; interface AdminConfiguration { @@ -49,10 +49,23 @@ function encryptSensitiveData(data: string): string { } 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'); 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) { console.error('[admin-config] Encryption failed:', error); return data; @@ -71,9 +84,33 @@ function decryptSensitiveData(encryptedData: string): string { } try { - const decipher = createDecipher('aes256', encryptionKey); - let decrypted = decipher.update(encryptedData, 'hex', 'utf8'); + // Check if data contains our modern format with colons + 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'); + return decrypted; } catch (error) { console.error('[admin-config] Decryption failed:', error);