我目前正在尝试运行可以与WebSocket通信的C ++服务器。 HandShake包含几个步骤,我在最后一个步骤中没有成功。
第一步是生成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论坛中找到了一个论坛条目,其中一个有同样的问题,答案是,我们应该传递20个字符的二进制表示,而不是传递40个字符的十六进制字符串。
我知道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];
}
现在是个大问题。如何将我的十六进制字符串转换为二进制?
提前多多感谢。 马库斯
修改
如果有人对代码感兴趣: https://github.com/MarkusPfundstein/C---Websocket-Server
答案 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;
}
答案 1 :(得分:1)
大多数Baser64编码器需要二进制数据的字节数组/流。您希望使用位掩码和逻辑移位将整数分成字节。在32位系统上,每个int包含4个字节,您可以按如下方式提取它们:
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倍的byte []。我假设这里的字节已被打包到int中,这可能是另一种方式。
将此字节[]传递到Base64编码器。
答案 2 :(得分:1)
稍微相关一点(我看到你已经发现了EVP BIO base64 way ...):
result[0] = 3011137324
...
oss << std::setw(8) << std::hex << result[i];
如果我理解正确,这会导致输出b37a4f2c
,这是您的IETF Docu示例。在这里要非常小心,因为你正在处理特定平台endianess的开放水域危险。 0n3011137324确实是0xb37a4f2c但仅在小端机器上,就像英特尔架构一样。您可能最好重新解释将&result[0]
强制转换为unsigned char*
,然后将其作为一个字节数组处理,而不是(无符号)整数数组。