node.js - AES-CBC 解密 node.js 与伪造数字信封例程:EVP_DecryptFinal_ex:bad decrypt
问题描述
我想用 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
这是 node.js 版本 14.15.0
解决方案
CBC 模式通常(包括这种情况)需要填充,并且您的加密使用填充,其中只有最后一个字节指定长度,其他字节是随机的。node-forge 显然接受了这一点,但 nodejs 内置crypto
使用 OpenSSL(特别是EVP_Decrypt*
API,如您在错误消息中所见),默认情况下实现PKCS5/7 填充,其中所有字节都必须包含长度。
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());
推荐阅读
- angular - Angular:serve 命令需要在 Angular 项目中运行,但找不到项目定义
- linux - nbd-client 设置设备失败
- angular - writeValue 不称为 Angular 自定义表单控件
- python - 使用 Python 将 XML 转换为 CSV - 无法正确返回结果
- vulkan - 并发使用 VkSamplers?
- pytorch - 有没有办法通过 Pytorch 对一组数据进行整体分类?
- swift - 错误:在没有更多上下文的情况下,表达式类型不明确
- java - 所有redis集群主节点数据都一样吗?
- bots.business - 如何在我们的网站内使用 bots 业务的 webhook 库?
- java - 单个 aws lambda 层中的多个 jar