如何使用nodejs解密cookie [英] How to decrypt cookie with nodejs

查看:203
本文介绍了如何使用nodejs解密cookie的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试运行此

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

//原始Cookie
VAR饼干= B417B464CA63FE780584563D2DA4709B03F6195189044C26A29770F3203881DD90B1428139088D945CF6807CA408F201DABBADD59CE1D740F853A894692273F1CA83EC3F26493744E3D25D720374E03393F71E21BE2D96B6110CB7AC12E44447FFBD810D3D57FBACA8DF5249EB503C3DFD255692409F084650EFED205388DD8C08BF7B941E1AC1B3B70B9A8E09118D756BEAFF25834E72357FD40E80E76458091224FAE8;

//来自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:数字信封例程:EVP_DecryptFinal_ex:错误的最终块长度

nodejs版本: 4.1.2和加密版本0.0.3



如何使用此算法正确解密Cookie,或者您可以建议任何其他?

解决方案

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



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



加密模式描述为这里,引用有趣的部分:


VERIFY + DECRYPT DATA(fEncrypt = false,signData = true)




  • 输入:buf表示要解密的密文,修饰符表示要从Ë输入(buf):E(iv + m +修饰符)+ HMAC(E(iv + m +修饰符))


  • 输出:m







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


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



哪些(希望)下面的脚本:

  //输入
VAR饼干= B417B464CA63FE780584563D2DA4709B03F6195189044C26A29770F3203881DD90B1428139088D945CF6807CA408F201DABBADD59CE1D740F853A894692273F1CA83EC3F26493744E3D25D720374E03393F71E21BE2D96B6110CB7AC12E44447FFBD810D3D57FBACA8DF5249EB503C3DFD255692409F084650EFED205388DD8C08BF7B941E1AC1B3B70B9A8E09118D756BEAFF25834E72357FD40E80E76458091224FAE8;
var decryptKey =FFA87B82D4A1BEAA15C06F6434A7EB2251976A838784E134900E6629B9F954B7;
var validationKey =A5326FFC9D3B74527AECE124D0B7BE5D85D58AFB12AAB3D76319B27EE57608A5A7BCAB5E34C7F1305ECE5AC78DB1FFEC0A9435C316884AB4C83D2008B533CFD9;

//参数
var hmacSize = 20

//为缓冲区输入
var cookieBuffer = new Buffer(cookie,'hex');
var decryptKeyBuffer = new Buffer(decryptKey,'hex');
var validationKeyBuffer = new Buffer(validationKey,'hex');

//解析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);

//验证HMAC
var crypto = require('crypto');
var h = crypto.createHmac('sha1',validationKeyBuffer);
h.update(cipherText);
var expectedHmac = h.digest();
console.log('预期的HMAC:'+ expectedHmac.toString('hex'));
console.log('实际HMAC:'+ hmac.toString('hex'));
//if(!expectedHmac.equals(hmac)){//注意:需要nodejs v0.11.13
// throw'Cookie完整性错误';
//}

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

// Strip IV
var res = new Buffer(plaintext.length-decryptKeyBuffer.length);
plaintext.copy(res,0,decryptKeyBuffer.length,plaintext.length);

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

给予结果:

 预期HMAC:88e332b9a27b8f6f8d805ae718c562c1c8b721ed 
实际HMAC:6beaff25834e72357fd40e80e76458091224fae8
HEX:010112ea9a47b2f2ce08fe121e7d78b6f2ce0801085400650073007400550073006500720016540065007300740020007400650073007400730073006f006e002c00200072006f006c0066007a006f007200012f00ff1d892908d9c497bd804f5f22eab043ff6368702c
UTF-8:绿} xTestUserTest testsson,rolfzor / ė O_ C chp,

有关此代码的一些(随机)注释: / p>


  • 它假定AES用于加密,HMAC-SHA1用于认证


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


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


  • '修饰符'字段为空。如果不是这样,您必须检查它,并从生产环境的明文


  • 中删除它,你绝对应该检查认证标签(否则你会暴露自己的讨厌的攻击)


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


  • IV长度等于密钥长度(请参阅 here 原因)




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



祝你好运!


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:

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

How can I properly decrypt cookie with this algorith or can you suggest any other?

解决方案

[Assuming you are trying to decrypt a .NET framework 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)

  • 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)
  • Input (buf): E(iv + m + modifier) + HMAC(E(iv + m + modifier))
  • Output: m

  • The 'iv' in the above descriptions isn't an actual IV. Rather, if ivType = > IVType.Random, we'll prepend random bytes ('iv') to the plaintext before feeding it to the crypto algorithms. 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. If ivType = IVType.Hash, we use a non-keyed hash of the plaintext.

  • 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
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

  • 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

  • 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). 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)

Disclaimer: I did not study the original .NET code thoroughly, nor am I a crypto expert so please do validate my thoughts

Good luck!

这篇关于如何使用nodejs解密cookie的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆