Skip to content

Instantly share code, notes, and snippets.

@reke592
Last active November 7, 2021 13:20
Show Gist options
  • Save reke592/acd17852e132b7c8dd0174500b658f31 to your computer and use it in GitHub Desktop.
Save reke592/acd17852e132b7c8dd0174500b658f31 to your computer and use it in GitHub Desktop.
Sample data encryption in nodejs
/** Sample usage:
*
* let _encrypt, _decrypt, _createIV;
*
* repo.useEncryption = async (encryption) => {
* if (!toString.call(_encrypt).match(/Function/)
* && !toString.call(_decrypt).match(/Function/)) {
* let config = encryption.configure([
* 'first_name',
* 'last_name',
* 'middle_name',
* 'mobile_number'
* ]);
* _encrypt = config.encrypt;
* _decrypt = config.decrypt;
* _createIV = config.createIV;
* }
* }
*
* repo.GetEncryptionKey = async (user_id, transaction) => {
* let user = await db.Users.findOne({
* where: {
* id: user_id
* },
* attributes: ['key_iv'],
* transaction
* });
*
* return user.key_iv;
* }
*
* repo.Insert = async (fields, transaction) => {
* let iv = await _createIV();
* let record = await db.Users.create({
* ... await _encrypt(fields, iv),
* key_iv: iv,
* date_created: new Date()
* }, {
* transaction
* });
*
* return record;
* }
*
* repo.GetById = async(id, transaction) => {
* let key_iv = await repo.GetEncryptionKey(id, transaction);
* let record = await db.Users.findOne({
* where: { id },
* transaction
* });
*
* return await _decrypt(record.dataValues, key_iv);
* // return record;
* }
*
*/
const crypto = require('crypto');
// const repo = require('../repositories/repository-db-config');
/**
* strict different key iv per user.
* decryption process requires the tbl_users.key_iv
*
* on user account removal, we will delete the tbl_users.key, as a result we will not be able to recover all the private details,
* but we still we preserve all the transactions made by the user for auditing purpose.
*/
/**
* Repository plugin for encryption
* @param {*} repo
* @returns factory { configure }
*/
module.exports = async function(repo) {
const algorithm = 'aes-256-cbc';
// Database private key, 32 bytes hex
let private_key = await repo.db_config.GetEncryptionKey();
/**
*
* @param {object} private_fields entity fields to apply encryption
* @param {object} repo repository implementation
* @returns {object} { encrypt, decrypt, createIV }
*/
const configure = (private_fields) => {
// key dictionary
_private_fields = {}
private_fields.forEach(key => {
_private_fields[key] = true;
})
/**
*
* @param {object} entity
* @param {string} key_iv d
* @returns {object} encrypted fields based on given private_fields in configuration
*/
const encrypt = async (entity, key_iv) => {
if (!key_iv) return entity;
Object.keys(entity).forEach(async key => {
if (_private_fields[key]) {
let cipher = crypto.createCipheriv(algorithm, Buffer.from(private_key, 'hex'), Buffer.from(key_iv, 'hex'));
let encryptedBuffer = cipher.update(entity[key]);
entity[key] = Buffer.concat([ encryptedBuffer, cipher.final() ]).toString('hex');
}
});
return entity;
}
/**
*
* @param {object} entity
* @param {string} key_iv
* @returns {object} decrypted fields based on given private_fields in configuration
*/
const decrypt = async (entity, key_iv) => {
if (!key_iv) return entity;
Object.keys(entity).forEach(async key => {
if (_private_fields[key]) {
let encrpytedBuffer = Buffer.from(entity[key], 'hex');
let cipher = crypto.createDecipheriv(algorithm, Buffer.from(private_key, 'hex'), Buffer.from(key_iv, 'hex'));
let decryptedBuffer = cipher.update(encrpytedBuffer);
entity[key] = Buffer.concat([ decryptedBuffer, cipher.final() ]).toString();
}
});
return entity;
}
const createIV = async () => {
return crypto.randomBytes(16).toString('hex');
}
return {
encrypt,
decrypt,
createIV
}
}
return {
configure
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment