Files
sap-erp/services/cryptoUtil.js
T
John 69b4e68baf
SAP-ERP Portal CI/CD / build (push) Failing after 5m20s
first commit
2026-09-23 17:31:02 +05:30

40 lines
1.6 KiB
JavaScript

// services/cryptoUtil.js
// Symmetric encryption for secrets we must be able to READ back (unlike
// portal passwords, which are one-way hashed) — specifically each user's SAP
// Service-Layer password, which has to be replayed to SAP at login time.
// AES-256-GCM with a key derived from JWT_SECRET. Output is a self-describing
// string "v1:<iv>:<tag>:<ciphertext>" (all base64), so decrypt needs no extra
// state. NOT for passwords you only ever compare — use hashing for those.
'use strict';
const crypto = require('crypto');
function key() {
const secret = process.env.JWT_SECRET || 'sap-portal-secret';
return crypto.createHash('sha256').update('sapcred:' + secret).digest(); // 32 bytes
}
function encrypt(plain) {
if (plain == null || plain === '') return '';
const iv = crypto.randomBytes(12);
const cipher = crypto.createCipheriv('aes-256-gcm', key(), iv);
const enc = Buffer.concat([cipher.update(String(plain), 'utf8'), cipher.final()]);
const tag = cipher.getAuthTag();
return `v1:${iv.toString('base64')}:${tag.toString('base64')}:${enc.toString('base64')}`;
}
function decrypt(blob) {
if (!blob) return '';
try {
const parts = String(blob).split(':');
if (parts.length !== 4 || parts[0] !== 'v1') return '';
const iv = Buffer.from(parts[1], 'base64');
const tag = Buffer.from(parts[2], 'base64');
const data = Buffer.from(parts[3], 'base64');
const decipher = crypto.createDecipheriv('aes-256-gcm', key(), iv);
decipher.setAuthTag(tag);
return Buffer.concat([decipher.update(data), decipher.final()]).toString('utf8');
} catch { return ''; }
}
module.exports = { encrypt, decrypt };