6

我正在尝试运行这个

function hex2a(hex) {
    var str = '';
    for (var i = 0; i < hex.length; i += 2)
        str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
    return str;
}

//Raw cookie
var cookie = "B417B464CA63FE780584563D2DA4709B03F6195189044C26A29770F3203881DD90B1428139088D945CF6807CA408F201DABBADD59CE1D740F853A894692273F1CA83EC3F26493744E3D25D720374E03393F71E21BE2D96B6110CB7AC12E44447FFBD810D3D57FBACA8DF5249EB503C3DFD255692409F084650EFED205388DD8C08BF7B941E1AC1B3B70B9A8E09118D756BEAFF25834E72357FD40E80E76458091224FAE8";

//decryptionKey from issuers <machineKey>
var deckey = "FFA87B82D4A1BEAA15C06F6434A7EB2251976A838784E134900E6629B9F954B7";


var crypto = require('crypto');

var ivc = cookie, iv, cipherText, ivSize = 16, res = "";

ivc = new Buffer(ivc, 'hex');
iv = new Buffer(ivSize);
cipherText = new Buffer(ivc.length - ivSize);
ivc.copy(iv, 0, 0, ivSize);
ivc.copy(cipherText, 0, ivSize);

c = crypto.createDecipheriv('aes-256-cbc', hex2a(deckey), iv.toString('binary'));
res = c.update(cipherText, "binary", "utf8");
res += c.final('utf8');


console.log(res);

在这个Q&A中,它提到了关于节点 js 版本的差异,我尝试应用那个但没有成功:

res = c.update(cipherText, "binary", "utf8");

线结果这样的结果

�sJ舸=�X7D������G����}x���T

res += c.final('utf8'); 

给出这个错误

0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length

nodejs 版本:4.1.2 和加密版本 0.0.3

我怎样才能用这个算法正确解密 cookie 或者你能建议任何其他的吗?

4

1 回答 1

6

[假设您正在尝试解密 .NET 框架 cookie]:

(注意:这个答案被完全重写,因为事情并不像看起来那么简单)

此处描述了加密模式,引用了有趣的部分:

验证 + 解密数据(fEncrypt = false,signData = true)

  • 输入: buf 表示要解密的密文,modifier 表示要从明文末尾删除的数据(因为它不是真正的明文数据)
  • 输入(buf):E(iv + m + 修饰符)+ HMAC(E(iv + m + 修饰符))
  • 输出:米

  • 上述描述中的“iv”不是实际的 IV。相反,如果 ivType = > IVType.Random,我们会将随机字节 ('iv') 添加到明文中,然后再将其提供给加密算法。在算法早期引入随机性可防止用户检查两个密文以查看明文是否相关。如果 ivType = IVType.None,则 'iv' 只是一个空字符串。如果 ivType = IVType.Hash,我们使用明文的非密钥散列。

  • 上述描述中的“修饰符”是一段元数据,应该与明文一起加密,但实际上并不是明文本身的一部分。它可用于存储生成此明文的用户名、生成明文的页面等内容。在解密时,修饰符参数与存储在加密流中的修饰符进行比较,并从返回明文之前的消息。

这是(希望)使用以下脚本实现的:

// Input
var cookie = "B417B464CA63FE780584563D2DA4709B03F6195189044C26A29770F3203881DD90B1428139088D945CF6807CA408F201DABBADD59CE1D740F853A894692273F1CA83EC3F26493744E3D25D720374E03393F71E21BE2D96B6110CB7AC12E44447FFBD810D3D57FBACA8DF5249EB503C3DFD255692409F084650EFED205388DD8C08BF7B941E1AC1B3B70B9A8E09118D756BEAFF25834E72357FD40E80E76458091224FAE8";
var decryptionKey = "FFA87B82D4A1BEAA15C06F6434A7EB2251976A838784E134900E6629B9F954B7";
var validationKey = "A5326FFC9D3B74527AECE124D0B7BE5D85D58AFB12AAB3D76319B27EE57608A5A7BCAB5E34C7F1305ECE5AC78DB1FFEC0A9435C316884AB4C83D2008B533CFD9";

// Parameters
var hmacSize=20

// Make buffers for input
var cookieBuffer = new Buffer(cookie, 'hex');
var decryptionKeyBuffer = new Buffer(decryptionKey, 'hex');
var validationKeyBuffer = new Buffer(validationKey, 'hex');

// Parse cookie
var curOffset=0;
var cipherText = new Buffer(cookieBuffer.length - hmacSize);
curOffset+=cookieBuffer.copy(cipherText, 0, curOffset, curOffset+cipherText.length);
var hmac = new Buffer(hmacSize);
curOffset+=cookieBuffer.copy(hmac, 0, curOffset, curOffset+hmac.length);

// Verify HMAC
var crypto = require('crypto');
var h = crypto.createHmac('sha1', validationKeyBuffer);
h.update(cipherText);
var expectedHmac = h.digest();
console.log('Expected HMAC: ' + expectedHmac.toString('hex'));
console.log('Actual   HMAC: ' + hmac.toString('hex'));
//if(!expectedHmac.equals(hmac)) { // Note: Requires nodejs v0.11.13
//    throw 'Cookie integrity error';
//}

// Decrypt
var zeroIv = new Buffer("00000000000000000000000000000000", 'hex');
var c = crypto.createDecipheriv('aes-256-cbc', decryptionKeyBuffer, zeroIv);
var plaintext = Buffer.concat([c.update(cipherText), c.final()]);

// Strip IV (which is the same length as decryption key -- see notes below)
var res = new Buffer(plaintext.length-decryptionKeyBuffer.length);
plaintext.copy(res, 0, decryptionKeyBuffer.length, plaintext.length);

// Output
console.log('HEX: ' + res.toString('hex'));
console.log('UTF-8: ' + res.toString('utf8'));

给出结果:

Expected HMAC: 88e332b9a27b8f6f8d805ae718c562c1c8b721ed
Actual   HMAC: 6beaff25834e72357fd40e80e76458091224fae8
HEX: 010112ea9a47b2f2ce08fe121e7d78b6f2ce0801085400650073007400550073006500720016540065007300740020007400650073007400730073006f006e002c00200072006f006c0066007a006f007200012f00ff1d892908d9c497bd804f5f22eab043ff6368702c
UTF-8: ��G���}x�TestUserTest testsson, rolfzor/���ė��O_"��C�chp,

关于此代码的一些(随机)注释:

  • 它假设 AES 用于加密,HMAC-SHA1 用于身份验证

  • 由于使用的身份验证密钥未知,完整性检查条件被注释掉并使用这个非常相关的问题的验证密钥(这是身份验证标签不匹配的原因)

  • 用于 AES 加密的填充是 PKCS#7

  • “修饰符”字段假定为空。如果不是这种情况,您将不得不检查它并将其从明文中删除

  • 对于生产环境,您绝对应该检查身份验证标签(否则您会将自己暴露在令人讨厌的攻击中)

  • 为了避免更严重的攻击,应该在恒定时间内测试身份验证标签的相等性(这在 nodejs 中实现可能很棘手)。请注意,注释掉的代码很可能容易受到时间攻击。

  • IV 长度等于密钥长度(原因见这里)

免责声明:我没有彻底研究原始 .NET 代码,也不是加密专家,所以请验证我的想法

祝你好运!

于 2016-10-09T22:29:00.233 回答