简体   繁体   English

如何使用nodejs解密cookie

[英]How to decrypt cookie with nodejs

I am trying to make run this 我想试试这个

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);

In this Q&A , it mentions about differences about node js versions, I tried that apply that one but with out success: 在这个Q&A中 ,它提到了有关节点js版本的差异,我试过应用那个,但没有成功:

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

line result such result 行结果这样的结果

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

and

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

gives this error 给出了这个错误

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

nodejs version: 4.1.2 and crypto version 0.0.3 nodejs version:4.1.2和crypto version 0.0.3

How can I properly decrypt cookie with this algorith or can you suggest any other? 如何使用此算法正确解密cookie,或者您可以建议其他任何?

[Assuming you are trying to decrypt a .NET framework cookie]: [假设您正在尝试解密.NET框架cookie]:

(Note: This answer was completely rewritten as things were not as simple as it seemed) (注意:这个答案完全重写了,因为事情并不像看起来那么简单)

The encryption schema is described here , citing interesting parts: 这里描述加密模式,引用了有趣的部分:

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

  • Input: buf represents ciphertext to decrypt, modifier represents data to be removed from the end of the plaintext (since it's not really plaintext data) 输入:buf表示要解密的密文,修饰符表示要从明文末尾删除的数据(因为它不是真正的纯文本数据)
  • Input (buf): E(iv + m + modifier) + HMAC(E(iv + m + modifier)) 输入(buf):E(iv + m +修饰符)+ HMAC(E(iv + m +修饰符))
  • Output: m 输出:m

  • The 'iv' in the above descriptions isn't an actual IV. 以上描述中的“iv”不是实际的IV。 Rather, if ivType = > IVType.Random, we'll prepend random bytes ('iv') to the plaintext before feeding it to the crypto algorithms. 相反,如果ivType => IVType.Random,我们会在将明文提供给加密算法之前将随机字节('iv')添加到明文中。 Introducing randomness early in the algorithm prevents users from inspecting two ciphertexts to see if the plaintexts are related. 在算法的早期引入随机性可以防止用户检查两个密文以查看明文是否相关。 If ivType = IVType.None, then 'iv' is simply an empty string. 如果ivType = IVType.None,则'iv'只是一个空字符串。 If ivType = IVType.Hash, we use a non-keyed hash of the plaintext. 如果ivType = IVType.Hash,我们使用明文的非键控哈希。

  • The 'modifier' in the above descriptions is a piece of metadata that should be encrypted along with the plaintext but which isn't actually part of the plaintext itself. 上面描述中的“修饰符”是一段元数据,应该与明文一起加密,但实际上并不是明文本身的一部分。 It can be used for storing things like the user name for whom this plaintext was generated, the page that generated the plaintext, etc. On decryption, the modifier parameter is compared against the modifier stored in the crypto stream, and it is stripped from the message before the plaintext is returned. 它可用于存储诸如生成此明文的用户名,生成明文的页面等内容。在解密时,将修饰符参数与存储在加密流中的修饰符进行比较,并将其从返回纯文本之前的消息。

Which is (hopefully) implemented with the following script: 哪个(希望)使用以下脚本实现:

// 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'));

Giving result: 给出结果:

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

Some (random) notes about this code: 关于此代码的一些(随机)注释:

  • it assumes that AES is used for encryption and HMAC-SHA1 is used for authentication 它假定AES用于加密,HMAC-SHA1用于身份验证

  • as the used authentication key is not known, the integrity check condition is commented out and verification key from this very related question is used (which is the reason for authentication tag mismatch) 因为使用的身份验证密钥未知,所以完整性检查条件被注释掉并且使用来自这个非常相关的问题的验证密钥(这是认证标签不匹配的原因)

  • the padding used for AES encryption is PKCS#7 用于AES加密的填充是PKCS#7

  • the 'modifier' field is assumed empty. “修饰符”字段假定为空。 If this is not the case you would have to check it and remove it from the plaintext 如果不是这种情况,您必须检查它并从明文中删除它

  • for production environment you definitely should check the authentication tag (otherwise you would expose yourself to nasty attacks) 对于生产环境,你肯定应该检查身份验证标记(否则你会暴露自己讨厌的攻击)

  • to avoid even nastier attacks, the authentication tag should be tested for equality in constant time (which might be tricky to implement in nodejs). 为了避免更严重的攻击,应该在恒定时间内测试身份验证标记是否相等(在nodejs中实现可能很棘手)。 Please note that the commented-out code is very probably vulnerable to timing-attacks. 请注意,注释掉的代码很可能容易受到时间攻击。

  • the IV length is equal to the key length (see here for the reason) IV长度等于密钥长度(见这里的原因)

Disclaimer: I did not study the original .NET code thoroughly, nor am I a crypto expert so please do validate my thoughts 免责声明:我没有彻底研究原始的.NET代码,也不是加密专家,所以请确认我的想法

Good luck! 祝好运!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM