const crypto = require('crypto'); const dotenv = require('dotenv'); dotenv.config(); const ALGORITHM = 'aes-256-gcm'; const IV_LENGTH = 16; const AUTH_TAG_LENGTH = 16; class EncryptionService { constructor() { let key = (process.env.ENCRYPTION_KEY || '').trim(); if (/^[0-9a-fA-F]{64}$/.test(key)) { key = key.substring(0, 32); } if (!key || key.length !== 32) { const raw = (process.env.ENCRYPTION_KEY || '').trim(); const preview = raw ? (raw.slice(0, 4) + '...' + raw.slice(-4)) : '(empty)'; const len = raw ? raw.length : 0; let fingerprint = ''; try { fingerprint = crypto.createHash('sha256').update(raw).digest('hex').slice(0, 16); } catch {} console.error('ENCRYPTION_KEY_RAW=', raw); console.error('Invalid ENCRYPTION_KEY: length=%s, preview=%s, hex64=%s, fingerprint=%s', String(len), preview, /^[0-9a-fA-F]{64}$/.test(raw) ? 'true' : 'false', fingerprint); if (String(process.env.ALLOW_WEAK_ENCRYPTION).toLowerCase() === 'true') { const weak = (raw || '').padEnd(32, '0').slice(0, 32); console.error('ALLOW_WEAK_ENCRYPTION enabled: using fallback key of length 32 to keep service alive'); this.encryptionKey = weak; return; } throw new Error('ENCRYPTION_KEY must be exactly 32 bytes long'); } this.encryptionKey = key; } /** * 生成用户特定的加密密钥(基于用户ID) */ generateUserKey(userId) { const userKey = crypto.createHash('sha256') .update(this.encryptionKey + userId.toString()) .digest('hex') .substring(0, 32); return userKey; } /** * 加密数据 */ encrypt(data, userId) { if (!data) return null; const userKey = this.generateUserKey(userId); const iv = crypto.randomBytes(IV_LENGTH); const cipher = crypto.createCipheriv(ALGORITHM, userKey, iv); let encrypted = cipher.update(data, 'utf8', 'hex'); encrypted += cipher.final('hex'); const authTag = cipher.getAuthTag(); // 返回 IV + AuthTag + EncryptedData return iv.toString('hex') + authTag.toString('hex') + encrypted; } /** * 解密数据 */ decrypt(encryptedData, userId) { if (!encryptedData) return null; try { const userKey = this.generateUserKey(userId); // 提取 IV、AuthTag 和加密数据 const iv = Buffer.from(encryptedData.substring(0, IV_LENGTH * 2), 'hex'); const authTag = Buffer.from( encryptedData.substring(IV_LENGTH * 2, IV_LENGTH * 2 + AUTH_TAG_LENGTH * 2), 'hex' ); const encrypted = encryptedData.substring(IV_LENGTH * 2 + AUTH_TAG_LENGTH * 2); const decipher = crypto.createDecipheriv(ALGORITHM, userKey, iv); decipher.setAuthTag(authTag); let decrypted = decipher.update(encrypted, 'hex', 'utf8'); decrypted += decipher.final('utf8'); return decrypted; } catch (error) { console.error('Decryption failed:', error); return null; } } /** * 加密服务器密码 */ encryptPassword(password, userId) { return this.encrypt(password, userId); } /** * 解密服务器密码 */ decryptPassword(encryptedPassword, userId) { return this.decrypt(encryptedPassword, userId); } /** * 加密私钥 */ encryptPrivateKey(privateKey, userId) { return this.encrypt(privateKey, userId); } /** * 解密私钥 */ decryptPrivateKey(encryptedPrivateKey, userId) { return this.decrypt(encryptedPrivateKey, userId); } } module.exports = new EncryptionService();