【问题标题】:NodeJS encryption: re-use cipher object to improve performanceNodeJS 加密:重用 cipher 对象以提高性能
【发布时间】:2014-03-23 23:04:29
【问题描述】:

我想要 nodejs 和一个加密的 MongoDB 数据库。我担心性能。考虑以下用例:

  1. 我有一个加密数据库,我从中检索加密字符串列表(例如名称) [_encrypted_name_1, _encrypted_name_2, ...]
  2. 我想解密该列表中的所有元素

由于我担心性能,我做了一些测试来弄清楚。 我观察到,与加密/解密非常大的字符串相比,加密/解密大量小字符串非常慢。

考虑以下示例:

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");

结果如下:

  • 慢:2078ms
  • 快速:20ms
  • for_loop: 14 毫秒
  • slow_nocrypt:1898 毫秒
  • fast_nocrypt:1 毫秒

大部分时间都花在创建 Cipher 对象上。因此,我想使用相同的密码对象来加密/解密字符串列表。在这种情况下,需要正确处理初始化向量:

  • 如何处理初始化向量?
  • 创建密码对象后,是否可以更改其初始化向量?

理想的场景可能是使用以下伪代码所示的流对象:

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));

【问题讨论】:

    标签: node.js mongodb encryption cryptography


    【解决方案1】:

    您的代码实际上很慢,因为对称算法在离散块中工作。

    当您加密单个字符串Your Name 时,密码会用随机字节填充它以达到块大小(128 位)的倍数。

    因此,您的慢速版本实际上是为每个字符串加密更多数据。

    为了加快速度,要么使用更小的块大小,要么每个块加密更多的数据。

    【讨论】:

    • AES 的块大小为 128 位。按照今天的标准,较小的块大小通常被认为是不安全的。
    • @ntoskrnl:他指定的是 256 位。
    • 这是密钥大小。 AES 针对 128、192 和 256 位密钥定义,但仅具有 128 位块大小。 AES 标准化的 Rijndael 支持其他几种块大小,但这些不在 AES 标准中。
    • 根据您的说法,如果我更新上述测试并将 myString 更改为“Your Name Your N”(128 位链接),那么长字符串和字符串列表之间应该没有区别。然而事实并非如此:字符串列表仍然慢 40 倍。大部分时间都花在创建密码对象上,这就是为什么我想知道是否可以重用一个并在调用之间更新初始化向量。谢谢你的帮助
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-11
    • 2011-07-30
    • 1970-01-01
    • 1970-01-01
    • 2015-11-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多