Reputation: 402
I've been testing the encryption/decryption performance of nodejs (well, crypto more specifically) to implement it in a project of mine. After a small amount of edits, I thought I had achieved a somewhat decent speed but then I talked to a friend and did some research, and now wish to know if there are any ways to do this more efficiently
I moved the require("crypto")
to outside the function so it only runs once, tried saving the cipher and decipher in a variable (which didn't work), googling more efficient ways to encrypt/decript,etc but couldn't achieve much more performance
var crypt = require('crypto')
function encrypt(text,password){
var text1=String(text)
var cipher = crypt.createCipher('aes-128-cbc',password)
var crypted = cipher.update(text1,'utf8','hex')
crypted += cipher.final('hex');
return crypted;
}
function decrypt(text,password){
var text1=String(text)
var decipher = crypt.createDecipher('aes-128-cbc',password)
var dec = decipher.update(text1,'hex','utf8')
dec += decipher.final('utf8');
return dec;
}
function generatepass(length) {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < length; i++){
text += possible.charAt(Math.floor(Math.random() * possible.length))
}
text=text.toString()
return text;
}
var text=generatepass(50)
var pass=generatepass(50)
aa=performance.now()
for(var i=0;i<1000;i++){
decrypt(encrypt(text,pass),pass)
}
console.log((performance.now()-aa)/1000) //around 0.05ms on my end
Upvotes: 4
Views: 5473
Reputation: 34113
Short recommendation: Use sodium-plus with sodium-native.
There are several reasons why sodium-plus will be a good move here:
sodium.crypto_secretbox()
and sodium.crypto_secretbox_open()
is superior here.generatepass()
function doesn't use a secure random number generator, but sodium-plus provides one.Your functions can be written as follows (using keys rather than passwords):
const { SodiumPlus } = require('sodium-plus');
let sodium;
async function encrypt(text, key) {
if (!sodium) sodium = await SodiumPlus.auto();
let nonce = await sodium.randombytes_buf(24);
let encrypted = await sodium.crypto_secretbox(text, nonce, key);
return Buffer.concat([nonce, encrypted]).toString('hex');
}
async function decrypt(ciphertext, key) {
if (!sodium) sodium = await SodiumPlus.auto();
const decoded = Buffer.from(ciphertext, 'hex');
const nonce = decoded.slice(0, 24);
const cipher = decoded.slice(24);
return sodium.crypto_secretbox_open(cipher, nonce, key);
}
async function randomString(length) {
if (!sodium) sodium = await SodiumPlus.auto();
const possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let text = "";
let r;
for (var i = 0; i < length; i++){
r = await sodium.randombytes_uniform(possible.length);
text += possible[r];
}
return text;
}
// Wrap this in an async function for calling:
(async function () {
if (!sodium) sodium = await SodiumPlus.auto()
var text = randomString(50)
var key = await sodium.crypto_secretbox_keygen()
let aa=performance.now()
for (var i=0; i<1000; i++) {
await decrypt(await encrypt(text, key), key)
}
console.log((performance.now()-aa)/1000)
})();
Note that the incumbent benchmark is also a bit misleading. Since this uses async functions, you can queue up a bunch of them at once and then resolve them all.
(async function () {
if (!sodium) sodium = await SodiumPlus.auto()
var text = randomString(50)
var key = await sodium.crypto_secretbox_keygen()
let aa=performance.now()
let queued = [];
for (var i=0; i<1000; i++) {
queued[i] = decrypt(await encrypt(text, key), key)
}
await Promise.all(queued);
console.log((performance.now()-aa)/1000)
})();
The main advantage of async functions for a Node.js web application is to prevent a single process from blocking the whole server for all users.
Upvotes: 2