Base64 encoding for Sec-WebSocket-Accept value

匿名 (未验证) 提交于 2019-12-03 08:44:33

问题:

A while ago, I started experimenting with WebSockets with Node.js taking care of the backend. It was working fine, but now when I return the protocol has been updated and I can't get it to work properly anymore.

Specifically, the problem is the Sec-WebSocket-Accept header. I seem to be doing something wrong when calculating it, although I can't really fathom what that might be. As far as I can tell, I'm following the instructions on Wikipedia to the dot.

Here's my code:

var magicString = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; var secWsKey = req.headers['sec-websocket-key']; var hash = require('crypto')              .createHash('SHA1')              .update(secWsKey + magicString)              .digest('hex'); var b64hash = new Buffer(hash).toString('base64'); var handshake = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" +             "Upgrade: WebSocket\r\n" +             "Connection: Upgrade\r\n" +             "Sec-WebSocket-Accept: " + b64hash + "\r\n" +             "\r\n";  socket.write(handshake);

An example connection:

// The incoming headers { upgrade: 'websocket',   connection: 'Upgrade',   host: 'localhost:8888',   origin: 'http://localhost:8888',   'sec-websocket-key': '4aRdFZG5uYrEUw8dsNLW6g==',   'sec-websocket-version': '13' }  // The outgoing handshake HTTP/1.1 101 Switching Protocols Upgrade: WebSocket Connection: Upgrade Sec-WebSocket-Accept: YTYwZWRlMjQ4NWFhNzJiYmRjZTQ5ODI4NjUwMWNjNjE1YTM0MzZkNg==  // Result: Error during WebSocket handshake: Sec-WebSocket-Accept mismatch

Looking more into this, I tried replicating the calculated hash in the wiki and it fails.

var hash = require('crypto')             .createHash('SHA1')             .update('x3JJHMbDL1EzLkh9GBhXDw==258EAFA5-E914-47DA-95CA-C5AB0DC85B11')             .digest('hex');  // Result  : 1d29ab734b0c9585240069a6e4e3e91b61da1969 // Expected: 1d29ab734b0c9585240069a6e4e3e91b61da1969  var buf = new Buffer(hash).toString('base64');  // Result  : MWQyOWFiNzM0YjBjOTU4NTI0MDA2OWE2ZTRlM2U5MWI2MWRhMTk2OQ== // Expected: HSmrc0sMlYUkAGmm5OPpG2HaGWk=

As you can see, the SHA1 hash is correct, but the base64 encoding is not. Looking at this answer, it seems I would be doing it right. I tried the same process in PHP and I get the same result, so clearly I'm Doing It Wrong.

I'm running Node.js v0.6.8.

Getting closer

Experimenting further with PHP, which is more familiar to me, and deriving from the behaviour of printf in the shell, I came up with this working snippet:

$hash = sha1('x3JJHMbDL1EzLkh9GBhXDw==258EAFA5-E914-47DA-95CA-C5AB0DC85B11'); $hashdec = ''; for ($i = 0; $i < strlen($hash); $i += 2) {      $hashdec .= chr(hexdec(substr($hash, $i, 2)));  }; echo base64_encode($hashdec); // Result  : HSmrc0sMlYUkAGmm5OPpG2HaGWk= // Expected: HSmrc0sMlYUkAGmm5OPpG2HaGWk=

I then tried to replicate this in JavaScript, but with no avail.

var magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; var key = "4aRdFZG5uYrEUw8dsNLW6g=="; var magic_key = magic + key; var hash = require('crypto').createHash('sha1').update(magic_key).digest('hex'); var buf = new Buffer(hash.length / 2);  for (var i = 0; i < hash.length; i += 2) {     var token = hash.substr(i, 2);     var int = parseInt(token.toString(16), 16);     var chr = String.fromCharCode(int);      buf.write(chr); }  console.log(buf.toString('base64'));  // Result  : w53dAAEAAADBIIAFAQAAAGGAtwA= // Expected: HSmrc0sMlYUkAGmm5OPpG2HaGWk=

回答1:

Sometimes reading the manual actually helps.

hash.digest([encoding])

Calculates the digest of all of the passed data to be hashed. The encoding can be 'hex', 'binary' or 'base64'.

(Emphasis mine.)

So the problem was solved by changing the code to:

var magicString = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; var secWsKey = req.headers['sec-websocket-key']; var hash = require('crypto')              .createHash('SHA1')              .update(secWsKey + magicString)              .digest('base64'); // <- see that, silly. var handshake = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" +             "Upgrade: WebSocket\r\n" +             "Connection: Upgrade\r\n" +             "Sec-WebSocket-Accept: " + hash + "\r\n" +             "\r\n";  socket.write(handshake);

'Tis time to feel silly. (Again.)



回答2:

use this http://pajhome.org.uk/crypt/md5/sha1.html and code

b64pad = "="; var b64hash = b64_sha1(secWsKey + magicString); console.log(b64hash);


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!