我已经在nodejs中重新实现了AES c ++解密。
“缓冲区”包含加密的内容。 “ decryptKey”包含解密“ buffer”的密钥。 “ expectedOutput”包含预期的输出。
为了绕过节点抛出的错误解密异常,我不得不在我的crypt对象中禁用autoPadding。
为简化起见,我添加了c ++代码,并向三种不同的算法(AES-128-ECB,AES-192-ECB,AES-256-ECB)添加了测试。没有解密结果与C ++输出匹配。
我想念什么?
var crypto = require('crypto');
var buffer = new Buffer([
0x5e,0x51,0xa3,0x53,0x9d,0xe7,0xe5,0xd3,
0xee,0x30,0xbb,0xf8,0x0c,0x72,0x9f,0x80
]);
var decryptKey = new Buffer([
0x36, 0x46, 0xb4, 0xf6,
0x8e, 0x6d, 0xdc, 0xf4,
0xb0, 0x31, 0x7e, 0x81,
0x6b, 0x5d, 0x96, 0x55
])
/*
After looking to my C++ code I noticed that despite of providing a 32 length key the 128 argument ensures that only the first 16 bytes are used
var decryptKey = new Buffer([
0x36, 0x46, 0xb4, 0xf6,
0x8e, 0x6d, 0xdc, 0xf4,
0xb0, 0x31, 0x7e, 0x81,
0x6b, 0x5d, 0x96, 0x55, // 16
0x15, 0x9c, 0x78, 0x54,
0x8c, 0xca, 0x3e, 0x39,
0x2d, 0x49, 0x75, 0x5d,
0xa1, 0x1a, 0xc3, 0xe3 // 32
])*/
var expectedOutput = new Buffer([
0xc8,0x6c,0x8f,0x2b,0xe8,0x21,0xc4,0x2e,
0xfb,0x4a,0x8e,0x8b,0xc3,0x94,0x19,0xc2
]);
// aes_context aes_ctx;
function decrypt(data, password, algorithm, padding){
if (padding === void 0) padding = true;
algorithm = algorithm || 'aes-128-ecb';
//aes_setkey_dec( &aes_ctx, digest, 128 );
var crypt = crypto.createDecipher(algorithm,password);
crypt.setAutoPadding(padding);
// aes_crypt_ecb( &aes_ctx, AES_DECRYPT, buffer, buffer );
var res = crypt.update(data, null, 'hex')
res += crypt.final('hex');
return new Buffer(res,'hex');
}
// aes_setkey_dec( &aes_ctx, digest, 128 );
var algoList = [
'aes-128-ecb',
'aes-192-ecb',
'aes-256-ecb'
];
for (var i = 0; i<= 1; i++){
console.log('\n ******* AUTO PADDING: ' + (padding ? 'ON': 'OFF') + ' ********* ');
var padding = i === 0;
for (let algo of algoList){
try {
var output = decrypt(buffer, decryptKey, algo, padding);
console.log(algo + ' => ' + output.toString('hex') + ' < ' + (Buffer.compare(expectedOutput, output) === 0 ? 'ok' : 'ko'))
} catch (err){
console.log('Failed to perform ' + algo + ' with autopadding ' + (padding ? ' on ': ' off ') + ' due to ' + err.message);
}
}
}
/*
******* AUTO PADDING: OFF *********
Failed to perform aes-128-ecb with autopadding on due to error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
Failed to perform aes-192-ecb with autopadding on due to error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
Failed to perform aes-256-ecb with autopadding on due to error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
******* AUTO PADDING: ON *********
aes-128-ecb => d9817f142f9bca262b67f6a6be570345 < ko
aes-192-ecb => 9181784373bb6060c04c9ba75de26322 < ko
aes-256-ecb => c5945203368de477e5f0dbeedeb2189f < ko
*/
这里有c ++代码
#include "aes.h"
#include "sha2.h"
int main(int argc, char *argv[]) {
unsigned char data[16] = {
0x5e,0x51,0xa3,0x53,0x9d,0xe7,0xe5,0xd3,0xee,0x30,0xbb,0xf8,0x0c,0x72,0x9f,0x80
};
unsigned char key[32] = {
0x36, 0x46, 0xb4, 0xf6,
0x8e, 0x6d, 0xdc, 0xf4,
0xb0, 0x31, 0x7e, 0x81,
0x6b, 0x5d, 0x96, 0x55, // 16
0x15, 0x9c, 0x78, 0x54,
0x8c, 0xca, 0x3e, 0x39,
0x2d, 0x49, 0x75, 0x5d,
0xa1, 0x1a, 0xc3, 0xe3 // 32
};
aes_context aes_ctx;
aes_setkey_dec(&aes_ctx, key, 128);
aes_crypt_ecb(&aes_ctx, AES_DECRYPT, data, data);
for (int i = 0; i< sizeof(data); ++i)
std::cout << std::hex << (int)data[i];
/* Output => c86c8f2be821c42efb4a8e8bc39419c2*/
}
引用:
基于以下答案的解决方案
var crypto = require('crypto')
var buffer = new Buffer([
0x5e,0x51,0xa3,0x53,0x9d,0xe7,0xe5,0xd3,
0xee,0x30,0xbb,0xf8,0x0c,0x72,0x9f,0x80
]);
var decryptKey = new Buffer([
0x36, 0x46, 0xb4, 0xf6,
0x8e, 0x6d, 0xdc, 0xf4,
0xb0, 0x31, 0x7e, 0x81,
0x6b, 0x5d, 0x96, 0x55
])
var expectedOutput = new Buffer([
0xc8,0x6c,0x8f,0x2b,0xe8,0x21,0xc4,0x2e,
0xfb,0x4a,0x8e,0x8b,0xc3,0x94,0x19,0xc2
]);
// aes_context aes_ctx;
function decrypt(data, password, algorithm, padding){
if (padding === void 0) padding = true;
algorithm = algorithm || 'aes-128-ecb';
//aes_setkey_dec( &aes_ctx, digest, 128 );
var crypt = crypto.createDecipheriv(algorithm,password, new Buffer([]));//new Buffer(32).fill(0).byteLength
crypt.setAutoPadding(padding);
// aes_crypt_ecb( &aes_ctx, AES_DECRYPT, buffer, buffer );
var res = crypt.update(data, null,'hex')
+ crypt.final('hex');
return new Buffer(res,'hex');
}
// aes_setkey_dec( &aes_ctx, digest, 128 );
var output = decrypt(buffer, decryptKey, 'aes-128-ecb', false);
console.log(Buffer.compare(expectedOutput, output) === 0 ? 'ok' : 'ko');
答案 0 :(得分:3)
已被弃用的 crypto.createDecypher()
派生 来自 password 参数的密钥:
crypto.createDecipher()
的实现使用OpenSSL函数EVP_BytesToKey
派生密钥,其摘要算法设置为MD5,一次迭代且无盐。
您要使用的是 原始 键。为此,您应该改用crypto.createDecipheriv()
:
var crypt = crypto.createDecipheriv(algorithm,password,new Buffer([]));
(在ECB模式下,IV可以为空)
当然,密钥长度必须匹配请求的算法(128、192或256位)。您的密钥是128位,因此只有aes-128-ecb将起作用。
答案 1 :(得分:0)
您需要将false
传递给setAutoPadding
的原因是,您的密文没有填充。您尚未包括生成密文的加密代码,但是我可以从它的长度得知它没有被填充,因为使用PKCS#7填充加密时,一个块大小的明文会生成密文。长度为两个块大小,而不是单个块。
使用aes_crypt_ecb
进行解密的原因是,看起来aes_crypt_ecb
仅执行单个块加密/解密,因此不不会执行任何填充或取消填充操作。不过,如果Javscript代码传递了true
到setAutoPadding
函数,则将期望填充(可能是PKCS#7)。当然会失败,因为您的加密没有使用 填充。
理想情况下,您应该修改加密代码,以便在进行加密时使用正确的填充,因为这比不使用填充要安全得多。否则,在进行解密时,您需要确保对setAutoPadding
的调用传递了false
,因此Javascript知道没有填充。