2012-05-13 145 views
2

我目前正在尝试运行一个可以与WebSocket通信的C++服务器。握手包括几个步骤,而我最后一个没有成功。Sha1的C++ Base64 - WebSocket握手

第一步是生成一个SHA1编码的字符串,我成功地获得了正确的十六进制字符串。 (示例http://en.wikipedia.org/wiki/WebSocket & http://tools.ietf.org/html/rfc6455)。

我的输出是在这两种情况下,如文档中所述的一样:

Wikipedia: 1d 29 ab 73 4b 0c 95 85 24 00 69 a6 e4 e3 e9 1b 61 da 19 69 
My Server: 1d 29 ab 73 4b 0c 95 85 24 00 69 a6 e4 e3 e9 1b 61 da 19 69 

IETF Docu: b3 7a 4f 2c c0 62 4f 16 90 f6 46 06 cf 38 59 45 b2 be c4 ea 
My Server: b3 7a 4f 2c c0 62 4f 16 90 f6 46 06 cf 38 59 45 b2 be c4 ea 

因此,这是正确的。当我现在做Base64编码时,我得出以下结果:

Wikipedia: HSmrc0sMlYUkAGmm5OPpG2HaGWk= 
My Server: MWQyOWFiNzM0YjBjOTU4NTI0MDA2OWE2ZTRlM2U5MWI2MWRhMTk2OQ== 

IETF Docu: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= 
My Server: YjM3YTRmMmNjMDYyNGYxNjkwZjY0NjA2Y2YzODU5NDViMmJlYzRlYQ== 

而这与此完全不同。我确认我的Base64算法适用于某些在线转换器,它们都生成了我的服务器的输出。所以问题是输入格式。我在一个javascript论坛中发现了一个论坛条目,其中一个有相同的问题,答案是,不是传递40个字符的十六进制字符串,而是传递20个字符的二进制表示。

我知道openssl SHA1返回一个二进制表示,但由于某些原因我无法使用这个库。我使用的SHA1库将编码后的输出放入一个int数组中。输出看起来像这样(IETF为例):

result[0] = 3011137324 
result[1] = 3227668246 
result[2] = 2432058886 
result[3] = 3476576581 
result[4] = 2998846698 

我这个转换比为十六进制是这样的:

std::ostringstream oss; 
oss << std::setfill('0'); 
      for (int i = 0; i < 5; ++i) { 
        oss << std::setw(8) << std::hex << result[i]; 
      } 

现在最大的问题。我如何将我的十六进制字符串转换为二进制?

非常感谢。 马库斯

EDIT

如果有人感兴趣的代码: https://github.com/MarkusPfundstein/C---Websocket-Server

回答

1

大多数Baser64编码器期望的二进制数据的字节数组/流。你想分割你的整数字节,使用位掩码和逻辑转换。

for(i = 0; i < 5; i++) { 

    byteResult[(i * 4) + 0] = result[i] & 0x000000ff; 
    byteResult[(i * 4) + 1] = (result[i] & 0x0000ff00) >> 8; 
    byteResult[(i * 4) + 2] = (result[i] & 0x00ff0000) >> 16; 
    byteResult[(i * 4) + 3] = (result[i] & 0xff000000) >> 24; 
} 

byteResult比结果阵列大的字节[] 4次:在32个的系统中,每个int包含4个字节,则可以如下提取它们。我假设这里的字节已经被装入了整数,这可能是相反的。

将此字节[]传递到Base64编码器中。

+0

真棒我会尽快尝试 –

+0

我很抱歉,但它没有工作:(结果是一个5的数组,所以我不得不枚举直到我<5它也会产生非常奇怪的输出 –

+0

抱歉,对于字节排序来说,输出是怎样的呢? –

2

我在c中测试websocket,发现字节顺序错误。适应的顺序(反向)解决了我的问题base64编码,从而正确接受密钥字符串:

unsigned char byteResult [20]; 
    for(i = 0; i < 5; i++) { 
     byteResult[(i * 4) + 3] = sha.result[i] & 0x000000ff; 
     byteResult[(i * 4) + 2] = (sha.result[i] & 0x0000ff00) >> 8; 
     byteResult[(i * 4) + 1] = (sha.result[i] & 0x00ff0000) >> 16; 
     byteResult[(i * 4) + 0] = (sha.result[i] & 0xff000000) >> 24; 
    } 
+0

谢谢。在这里你可以看到我如何修复它(方法Connection :: Authenticate()https://github.com/MarkusPfundstein/C---Websocket-Server/blob/master/Network/Connection.cc –

1

在一个稍微有关说明(我看你已经发现了EVP BIO base64 way ...):

result[0] = 3011137324 
... 
oss << std::setw(8) << std::hex << result[i]; 

如果我理解正确的话这将导致输出b37a4f2c,这是你的IETF的Docu例子。在这里要非常小心,因为你在平台特定的endianess的开放水域危险中穿梭。 0n3011137324确实是0xb37a4f2c,但是只在小端机器上,像Intel体系结构一样。你可能会更好,重新解释将&result[0]转换为unsigned char*,然后将其作为一个字节数组来处理,而不是一组(无符号)整数。