2

我目前正在尝试运行可以与 WebSocket 通信的 C++ 服务器。HandShake 由几个步骤组成,最后一个步骤我没有成功。

第一步是生成一个 SHA1 编码的字符串,我成功获得了正确的十六进制字符串。(例如http://en.wikipedia.org/wiki/WebSockethttps://www.rfc-editor.org/rfc/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

4

3 回答 3

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;
    }
于 2012-08-16T09:46:23.627 回答
1

在一个稍微相关的注释上(我看到你已经发现了EVP BIO base64 方式......):

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

如果我理解正确,这会导致 output b37a4f2c,这是您的 IETF Docu 示例。在这里要非常小心,因为您正在关注平台特定字节序的开放水域危险。0n3011137324 确实是 0xb37a4f2c 但仅在小端机器上,如英特尔架构。您可能最好重新解释强制&result[0]转换为unsigned char*,然后将其作为字节数组处理,而不是(无符号)整数数组。

于 2012-08-16T12:12:40.123 回答
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;
}

其中byteResultbyte[] 比结果数组大 4 倍。我假设字节被打包到这里的整数的顺序,它可能是相反的。

将此 byte[] 传递到您的 Base64 编码器中。

于 2012-05-13T13:27:01.843 回答