EVP_DecryptFinal_ex:使用Node.js时解密不良

Son*_*oor 9 encryption openssl cryptography node.js node-crypto

使用以下节点js:

var crypto = require('crypto');
var encrypt = function (input, password, callback) {
    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');
    console.log(iv);

    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');
    callback(encoded);
};

var decrypt = function (input, password, callback) {
    // Convert urlsafe base64 to normal base64
    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');

    callback(plaintext);
};
Run Code Online (Sandbox Code Playgroud)

为了执行,我运行了这个:

encrypt("uWeShxRrCKyK4pcs", "secret", function (encoded) {
    console.log(encoded);
    decrypt(encoded, "secret", function (output) {
        console.log(output);
    });
});
Run Code Online (Sandbox Code Playgroud)

加密似乎工作正常,但当我尝试解密时,我收到以下错误:

错误:错误:06065064:数字信封例程:EVP_DecryptFinal_ex:在Decipheriv.Cipher.final处于错误(本机)时解密错误(crypto.js:202:26)

我对密码学很陌生,所以不知道为什么我收到这个错误.我现在只需修好它.

Art*_* B. 8

你混合了两种不同的编码.看到

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

cipher.final([output_encoding])

现在来看看

var encrypted = cipher.update(data, 'binary') + cipher.final('binary');
Run Code Online (Sandbox Code Playgroud)

但它应该是

var encrypted = cipher.update(data, 'binary', 'binary') + cipher.final('binary');
Run Code Online (Sandbox Code Playgroud)

问题是cipher.update(data, 'binary')输出一个缓冲区,它自动字符串化为十六进制编码的字符串而不是"二进制"字符串.


无论如何,这段代码有很多错误,你应该重新开始,只需使用一个高度自以为是的现有库.

  • 必须有一个随机的IV,它被加在密文之前,以达到语义安全.

  • 密码具有低熵,不能用作密钥.单个MD5调用不会改变这一事实.密码的密钥派生应该是缓慢的,因此使用具有高迭代计数/成本因子的已知方案,例如PBKDF2,bcrypt,scrypt或Argon2(增加安全性).不要忘记盐.

  • 在加密然后MAC方案中使用消息认证代码(例如HMAC-SHA256)验证密文.否则,攻击者可能会操纵密文,您甚至无法检测到更改.使用填充oracle攻击丢失数据的第一步.


小智 5

由于这个问题是第一个出现在 Google 上的问题,因此这里有另一个解决方案。

救生员解密失败

如果链接断开,就我而言,我必须更新解密函数以添加

function decrypt(text) {
    let iv = Buffer.from((text.split(':')[1]).split('=')[0], 'hex')//will return iv;
    let enKey = Buffer.from(text.split('=')[1], 'hex')//will return key;
    let encryptedText = Buffer.from(text.split(':')[0], 'hex');//returns encrypted Data
    let decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(enKey), iv);
// Added this line here
    decipher.setAutoPadding(false);
    let decrypted = decipher.update(encryptedText);
    decrypted = Buffer.concat([decrypted, decipher.final()]);
    return decrypted.toString();
    //returns decryptedData
}
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

7954 次

最近记录:

6 年,3 月 前