I would like to nodejs and an encrypted MongoDB database. I am concerned about performance. Consider the following use case:
Since I am concerned about performance I did some tests to figure it out. I observed that encrypting/decrypting lots of small strings is very slow compared to encrypting/decrypting a very large string.
Consider the following example:
var crypto = require('crypto'),
_ = require('lodash'),
encryptedStringArray = [],
decryptedStringArray = [],
encryptedLongString,
NB_ITERATION = 100000,
stringArray = [],
longString = '',
myString = 'Your Name';
function encrypt(text){
var cipher = crypto.createCipher('aes-256-cbc', 'd6F3Efeq');
var crypted = cipher.update(text, 'utf8', 'hex');
crypted += cipher.final('hex');
return crypted;
}
function decrypt(text){
var decipher = crypto.createDecipher('aes-256-cbc', 'd6F3Efeq');
var dec = decipher.update(text, 'hex', 'utf8');
dec += decipher.final('utf8');
return dec;
}
// SLOW: ARRAY OF STRINGS
console.time("slow");
for (var i = 0; i < NB_ITERATION; i += 1) {
stringArray.push(myString);
}
_.forEach(stringArray, function (item) {
encryptedStringArray.push(encrypt(item));
});
_.forEach(encryptedStringArray, function (item) {
decryptedStringArray.push(decrypt(item)); //.toString());
});
console.timeEnd("slow");
// FAST: SUPER LONG STRING
console.time("fast");
for (var i = 0; i < NB_ITERATION; i += 1) {
longString += myString;
}
encryptedLongString = encrypt(longString);
decrypt(encryptedLongString);
console.timeEnd("fast");
// **********************************************************************
// FOR LOOP
// **********************************************************************
//
console.time("for_loop");
stringArray = [];
encryptedStringArray = [];
decryptedStringArray = [];
for (var i = 0; i < NB_ITERATION; i += 1) {
stringArray.push(myString);
}
_.forEach(stringArray, function (item) {
encryptedStringArray.push(myString);
});
_.forEach(encryptedStringArray, function (item) {
decryptedStringArray.push(myString);
});
console.timeEnd("for_loop");
// **********************************************************************
// CREATION OF CIPHER ONLY - NO ENCRYPTION
// **********************************************************************
function noencrypt(text){
var cipher = crypto.createCipher('aes-256-cbc', 'd6F3Efeq');
// var crypted = cipher.update(text, 'utf8', 'hex');
// crypted += cipher.final('hex');
// return crypted;
return text;
}
function nodecrypt(text){
var decipher = crypto.createDecipher('aes-256-cbc', 'd6F3Efeq');
// var dec = decipher.update(text, 'hex', 'utf8');
// dec += decipher.final('utf8');
// return dec;
return text;
}
// SLOW
console.time("slow_nocrypt");
for (var i = 0; i < NB_ITERATION; i += 1) {
stringArray.push(myString);
}
_.forEach(stringArray, function (item) {
encryptedStringArray.push(noencrypt(item));
});
_.forEach(encryptedStringArray, function (item) {
decryptedStringArray.push(nodecrypt(item)); //.toString());
});
console.timeEnd("slow_nocrypt");
// FAST
console.time("fast_nocrypt");
for (var i = 0; i < NB_ITERATION; i += 1) {
longString += myString;
}
encryptedLongString = noencrypt(longString);
nodecrypt(encryptedLongString);
console.timeEnd("fast_nocrypt");
Here are the results:
Most of the time is spent creating Cipher objects. Therefore, I would like to use the same cipher object to encrypt/decrypt a list of of strings. In this case one needs to properly deal with the initialisation vector:
The ideal scenario would probably be to use stream objects illustrated by the following pseudo-code:
var myArray = [
{to_encrypt: 'Your Name 1', iv: INIT_VECTOR_1},
{to_encrypt: 'Your Name 2', iv: INIT_VECTOR_2}];
var encrypted_array = [];
streamify(myArray)
.pipe(CIPHER_WITH_IV_UPDATE)
.write(streamify(encrypted_array));
Your code is actually slow because symmetric algorithms work in discrete blocks.
When you encrypt the single string Your Name, the cipher will pad it with random bytes to reach a multiple of the block size (128 bits).
Therefore, your slow version is actually encrypting more data per string.
To speed it up, either use a smaller block size or encrypt more data per block.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With