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

line 結果 そのような結果

�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 を復号化しようとしていると仮定して]:

(注:物事が思ったほど単純ではなかったため、この回答は完全に書き直されました)

暗号化スキーマは、興味深い部分を引用して、ここで説明されています。

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

  • 入力: buf は復号化する暗号文を表し、modifier は平文の末尾から削除するデータを表します (実際には平文データではないため)
  • 入力 (buf): E(iv + m + 修飾子) + HMAC(E(iv + m + 修飾子))
  • 出力: m

  • 上記の説明の「iv」は実際の IV ではありません。むしろ、ivType = > IVType.Random の場合は、平文を暗号化アルゴリズムに供給する前に、ランダムなバイト ('iv') を平文の先頭に追加します。アルゴリズムの早い段階でランダム性を導入すると、ユーザーは 2 つの暗号文を検査して平文が関連しているかどうかを確認できなくなります。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 に答える