File size: 1,941 Bytes
ad573c0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8dde1b0
ad573c0
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import crypto from 'crypto';
import fs from 'fs/promises';
import path from 'path';

const ALGORITHM = 'aes-256-gcm';
const KEY_LENGTH = 32; // 256 bits
const IV_LENGTH = 16; // 128 bits for GCM
const AUTH_TAG_LENGTH = 16; // 128 bits

// Derive key from environment variable
function getKey() {
  const keyEnv = process.env.DATA_ENCRYPTION_KEY;
  if (!keyEnv) throw new Error('DATA_ENCRYPTION_KEY environment variable not set');
  // Use SHA-256 to derive a 32-byte key from the env var
  return crypto.createHash('sha256').update(keyEnv).digest();
}

export function encryptJson(data) {
  const key = getKey();
  const iv = crypto.randomBytes(IV_LENGTH);
  const cipher = crypto.createCipher(ALGORITHM, key);
  cipher.setAAD(Buffer.from('')); // Optional AAD

  let encrypted = cipher.update(JSON.stringify(data), 'utf8', 'hex');
  encrypted += cipher.final('hex');

  const authTag = cipher.getAuthTag();
  return {
    iv: iv.toString('hex'),
    encrypted,
    authTag: authTag.toString('hex'),
  };
}

export function decryptJson(encryptedData) {
  const key = getKey();
  const { iv, encrypted, authTag } = encryptedData;
  const decipher = crypto.createDecipher(ALGORITHM, key);
  decipher.setAuthTag(Buffer.from(authTag, 'hex'));
  decipher.setAAD(Buffer.from('')); // Match AAD

  let decrypted = decipher.update(encrypted, 'hex', 'utf8');
  decrypted += decipher.final('utf8');
  return JSON.parse(decrypted);
}

export async function saveEncryptedJson(filePath, data) {
  const encrypted = encryptJson(data);
  await fs.mkdir(path.dirname(filePath), { recursive: true });
  await fs.writeFile(filePath, JSON.stringify(encrypted));
}

export async function loadEncryptedJson(filePath) {
  try {
    const content = await fs.readFile(filePath, 'utf8');
    const encrypted = JSON.parse(content);
    return decryptJson(encrypted);
  } catch (err) {
    if (err.code === 'ENOENT') return null; // File not found
    throw err;
  }
}