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



我有两个函数来加密和解密node.js中的字符串,两者都工作得很好,直到输入字符串的长度小于15个字符,以上它们将不起作用。下面是在nodejs中使用crypto模块的两个函数。

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

请帮我解决这个问题。

让我们看一下文档:

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

你在做

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

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

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

[Error: Error: 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');

其他注意事项:

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

您有一个小IV,限制为15个字符。IV的长度应该与纯文本相等。您可以多次重复您的键以生成一个大IV。

最新更新