Skip to content

Instantly share code, notes, and snippets.

@tsmx
Last active October 10, 2020 18:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tsmx/d6a19f8e71bf764a2563dd6a2bd22a4d to your computer and use it in GitHub Desktop.
Save tsmx/d6a19f8e71bf764a2563dd6a2bd22a4d to your computer and use it in GitHub Desktop.
Encryption-at-rest in MongoDB with Mongoose getters/setters and NodeJS Crypto.
const crypto = require('crypto');
const algorithm = 'aes-256-cbc';
const dbURI = 'mongodb://localhost/encryptiontest';
const dbOptions = {
user: 'encryptiontest',
pass: 'test',
useNewUrlParser: true,
useCreateIndex: true,
useFindAndModify: false,
useUnifiedTopology: true
};
function encrypt(text) {
let key = process.env.ENCRYPTION_KEY;
let iv = crypto.randomBytes(16);
let cipher = crypto.createCipheriv(algorithm, key, iv);
let encrypted = cipher.update(text);
encrypted = Buffer.concat([encrypted, cipher.final()]);
return iv.toString('hex') + '|' + encrypted.toString('hex');
};
function decrypt(text) {
let key = process.env.ENCRYPTION_KEY;
let decrypted = null;
try {
let input = text.split('|');
let iv = Buffer.from(input[0], 'hex');
let encryptedText = Buffer.from(input[1], 'hex');
let decipher = crypto.createDecipheriv(algorithm, key, iv);
decrypted = decipher.update(encryptedText);
decrypted = Buffer.concat([decrypted, decipher.final()]);
}
catch (error) {
throw new Error('Decryption failed. Please check that the encrypted secret is valid');
}
return decrypted.toString();
};
var mongoose = require('mongoose');
var Visitor = mongoose.model('Visitor', {
firstName: { type: String, get: decrypt, set: encrypt },
lastName: { type: String, get: decrypt, set: encrypt },
});
process.env.ENCRYPTION_KEY = '00000000000000000000000000000000';
mongoose.connect(dbURI, dbOptions);
mongoose.connection.once('open', async function () {
const visitor = new Visitor();
visitor.firstName = 'Hans';
visitor.lastName = 'Müller';
let savedVisitor = await visitor.save();
console.log('=== save ===');
console.log('Saved ID: ' + savedVisitor._id.toString());
let retrievedVisitor = await Visitor.findById(savedVisitor._id);
console.log('=== findById (proove successful decryption) ===');
console.log('Found ID: ' + retrievedVisitor._id.toString());
console.log('Found firstName: ' + retrievedVisitor.firstName);
console.log('Found firstName: ' + retrievedVisitor.lastName);
let retrievedVisitorLean = await Visitor.findById(savedVisitor._id).lean();
console.log('=== findById.lean (proove encryption-at-rest) ===');
console.log('Lean ID: ' + retrievedVisitorLean._id);
console.log('Lean firstName: ' + retrievedVisitorLean.firstName);
console.log('Lean firstName: ' + retrievedVisitorLean.lastName);
mongoose.connection.close(function () {
process.exit(0);
});
});
// example output:
//
// === save ===
// Saved ID: 5f80d1ceafd13c33ef94312c
// === findById (proove successful decryption) ===
// Found ID: 5f80d1ceafd13c33ef94312c
// Found firstName: Hans
// Found firstName: Müller
// === findById.lean (proove encryption-at-rest) ===
// Lean ID: 5f80d1ceafd13c33ef94312c
// Lean firstName: 54859787d74b8dac37a741265c608c16|585d9c05937ea833bcc7c9282e8f41db
// Lean firstName: c4f03e01125061b7341f6dcac97f2bd1|eb1016dff587de0bf80daa91ecf2771f
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment