AES-CBC解密node.js与伪造数字信封例程:EVP_DecryptFinal_ex:错误解密

时间:2020-11-06 02:48:24

标签: node.js encryption aes

我想使用node.js的一部分解密来解密某些内容,但收到错误消息。如果我对相同的输入数据使用伪造,则可以解密数据。在nodeDecrypt函数中我怎么了?

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 = decipher.update(encrypted);

    console.log(decrypted.toString());
    try {
        decrypted += decipher.final();
    } catch (e) {
        console.log(e);
    }
    
    return decrypted;
}

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 });
    decipher.update(forge.util.createBuffer(encrypted));
    var result = decipher.finish();
    return decipher.output.getBytes();
}
var decrypted;

decrypted = nodeDecrypt(encryptedBuffer, userKey);
console.log(decrypted.toString());

decrypted = forgeDecrypt(encryptedBuffer, userKey);
console.log(decrypted.toString());

输出

1a24989e-75d1-4631-8210-b17bb5e6
decryptor.js:26
Error: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
    at Decipheriv.final (<node_internals>/internal/crypto/cipher.js:174:29)
...
    at internal/main/run_main_module.js:17:47 {library: 'digital envelope routines', function: 'EVP_DecryptFinal_ex', reason: 'bad decrypt', code: 'ERR_OSSL_EVP_BAD_

1a24989e-75d1-4631-8210-b17bb5e6

1a24989e-75d1-4631-8210-b17bb5e6a2a1

这是与nodes.js 14.15.0版本一起使用的

1 个答案:

答案 0 :(得分:1)

CBC模式通常(包括这种情况)需要填充,而加密使用填充,其中只有最后一个字节指定长度,而其他字节是随机的。 node-forge显然接受了这一点,但是内置crypto的nodejs使用OpenSSL(特别是EVP_Decrypt* API,您可以在错误消息中看到)由by default实现的PKCS5/7 padding,其中< em>所有字节必须包含长度。

OpenSSL和crypto确实可以选择根本不执行任何填充和取消填充操作,而您可以自己完成。您可以在此处使用该选项,如下所示:

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);
    decipher.setAutoPadding(false);
    encrypted = encrypted.slice(16);
    var decrypted = Buffer.concat([decipher.update(encrypted),decipher.final()]);
    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 });
    decipher.update(forge.util.createBuffer(encrypted));
    var result = decipher.finish();
    return decipher.output.getBytes();
}
var decrypted;

decrypted = nodeDecrypt(encryptedBuffer, userKey);
console.log(decrypted.toString());

decrypted = forgeDecrypt(encryptedBuffer, userKey);
console.log(decrypted.toString());