Node.js Crypto仅适用于长度小于15的字符串

时间:2015-09-28 10:13:03

标签: node.js encryption

我有两个函数来加密和解密node.js中的字符串,两者都工作正常,直到输入字符串的长度小于15个字符,超过这个它们将无法工作。下面是我在带有加密模块的nodejs中使用的函数。

encrypt: function (input, password) {
    try{
        input = input.toString();
        var m = crypto.createHash('md5');
        m.update(password);
        var key = m.digest('hex');

        m = crypto.createHash('md5');
        m.update(password + key);
        var iv = m.digest('hex');

        var data = new Buffer(input, 'utf8').toString('binary');

        var cipher = crypto.createCipheriv('aes-256-cbc', key, iv.slice(0,16));
        var encrypted = cipher.update(data, 'binary') + cipher.final('binary');
        var encoded = new Buffer(encrypted, 'binary').toString('base64');

        return encoded;
    }catch (ex) {
        return input;
    }
 },


 decrypt: function (input, password) {
     try{
        // Convert urlsafe base64 to normal base64
        var input = input.replace(/\-/g, '+').replace(/_/g, '/');
        // Convert from base64 to binary string
        var edata = new Buffer(input, 'base64').toString('binary');

        // Create key from password
        var m = crypto.createHash('md5');
        m.update(password);
        var key = m.digest('hex');

        // Create iv from password and key
        m = crypto.createHash('md5');
        m.update(password + key);
        var iv = m.digest('hex');

        // Decipher encrypted data
        var decipher = crypto.createDecipheriv('aes-256-cbc', key, iv.slice(0,16));
        var decrypted = decipher.update(edata, 'binary') + decipher.final('binary');  
        var plaintext = new Buffer(decrypted, 'binary').toString('utf8');
        return plaintext;
     }catch (ex) {
         return input;
     }
  }

请帮我解决这个问题。

2 个答案:

答案 0 :(得分:1)

让我们看看文档:

cipher.update(data[, input_encoding][, output_encoding])
cipher.final([output_encoding])

你正在做

var encrypted = cipher.update(data, 'binary') + cipher.final('binary');

这意味着update()调用返回一个Buffer,因为你没有指定输出编码,final()输出二进制字符串。

当缓冲区通过连接强制转换为字符串时,这两个部分具有不同的编码,并且因为您将其作为new Buffer(encrypted, 'binary')的单个部分读取,它将在解密期间抛出错误:

  

[错误:错误:0606506D:数字包络例程:EVP_DecryptFinal_ex:错误的最终块长度]

查看抛出的异常总是一个好主意。目前,如果引发异常,您只是忽略异常ex

解决方案

在加密期间提供输出编码:

var encrypted = cipher.update(data, 'binary', 'binary') + cipher.final('binary');

和解密:

var decrypted = decipher.update(edata, 'binary', 'binary') + decipher.final('binary');

其他考虑因素:

密钥和IV应由字节组成。目前,您正在使用MD5生成256位的十六进制编码密钥。相反,您应该使用二进制输出大小为384位的PBKDF2(数千或数百万次迭代和随机盐)。您可以将前256位用于密钥,其余用于IV。然后你将盐与密文一起发送。

答案 1 :(得分:-3)

你有一个小的IV,它限制为15个字符。 IV的长度应与纯文本相同。您可以多次重复您的密钥以生成大型IV。