node.jsencryptionopensslcryptographynode-crypto

EVP_DecryptFinal_ex:bad decrypt when using Node.js


Using the following node 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);
};

To execute I ran this:

encrypt("uWeShxRrCKyK4pcs", "secret", function (encoded) {
    console.log(encoded);
    decrypt(encoded, "secret", function (output) {
        console.log(output);
    });
});

Encrypting seems to work fine, but when I try to decrypt, I receive the following error:

Error: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt at Error (native) at Decipheriv.Cipher.final (crypto.js:202:26)

I am pretty new to cryptography, so don't really know why I am receiving this error. I just need to get it fixed for now.


Solution

  • You mixed up two different encodings. See

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

    and

    cipher.final([output_encoding])

    and now look at

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

    Here the square brackets denote an optional function input. If you pass more values than are required then the additional values will be matched to the optional inputs from the left.

    It should be

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

    The issue is that cipher.update(data, 'binary') outputs a buffer which automatically stringifies to a Hex-encoded string instead of a "binary"-string.


    Anyway, there is so much wrong with this code that you should start over and simply use an existing library that is highly opinionated.