AES-CBC decryption node.js vs. forge digital envelope routines:EVP_DecryptFinal_ex:bad decrypt

CBC mode generally (including this case) needs padding, and your encryption uses padding where only the last byte specifies the length and the other bytes are random. node-forge evidently accepts this, but nodejs builtin crypto uses OpenSSL (specifically the EVP_Decrypt* API, as you can see in the error message) which by default implements PKCS5/7 padding where all bytes must contain the length.

OpenSSL, and crypto, does have an option to not do any padding and unpadding at all, leaving you to do it yourself. You can use that option here as follows:

const crypto = require('crypto');

const keyHash = "b6db3d66f4f8bd82aea61576e221f23634bb7c585340a8a42140701f5a468e04"
const encryptedB64 = "cHIaTs0vA6phV8jyT3X78cTSrUnLeBwbAqstVBAl7kl4uV+4oGQFVgsChW8lfw4QOyECkZAay7c0rDi816T9ZA==";

const encryptedBuffer = Buffer.from(encryptedB64, 'base64');

var userKey = Buffer.from(keyHash, 'hex');

const forge = require('node-forge');

function nodeDecrypt(encrypted, key) {
    const iv = encrypted.slice(0, 16);
    const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
    encrypted = encrypted.slice(16);
    var decrypted = Buffer.concat([decipher.update(encrypted),]);
    var padlen = decrypted[decrypted.length-1];    
    return decrypted.slice(0,decrypted.length-padlen);

function forgeDecrypt(encrypted, key) {
    const encoding = 'latin1';
    key = key.toString(encoding);
    initVal = encrypted.toString(encoding).substring(0, 16);
    encrypted = encrypted.toString(encoding).substring(16);
    var decipher = forge.cipher.createDecipher('AES-CBC', key);
    decipher.start({ iv: initVal });
    var result = decipher.finish();
    return decipher.output.getBytes();
var decrypted;

decrypted = nodeDecrypt(encryptedBuffer, userKey);

decrypted = forgeDecrypt(encryptedBuffer, userKey);

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top