2

現在、WebSocket と通信できる C++ サーバーを実行しようとしています。HandShake はいくつかのステップで構成されており、最後のステップではうまくいきません。

最初のステップは、SHA1 でエンコードされた文字列を生成することで、正しい 16 進文字列を正常に取得できました。(例http://en.wikipedia.org/wiki/WebSocket & https://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 フォーラムでフォーラム エントリを見つけました。答えは、40 文字の 16 進文字列を渡す代わりに、20 文字のバイナリ表現を渡す必要があるというものでした。

openssl SHA1 がバイナリ表現を返すことは知っていますが、特定の理由でライブラリを使用できません。私が使用するSHA1ライブラリは、エンコードされた出力をint配列に入れます。出力は次のようになります (IETF の例)。

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

私はこれを次のように16進数に変換します:

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

今、大きな問題です。16 進文字列をバイナリに変換するにはどうすればよいですか?

よろしくお願いします。マーカス

編集

誰かがコードに興味がある場合: 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

ほとんどの Baser64 エンコーダーは、バイナリ データのバイト配列/ストリームを想定しています。ビット マスクと論理シフトを使用して、int をバイトに分割します。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 にパックされた順序を想定していますが、逆の場合もあります。

この byte[] を Base64 エンコーダーに渡します。

于 2012-05-13T13:27:01.843 に答える
1

少し関連するメモについて ( EVP BIO base64 の方法を既に発見したようです...):

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

私が正しく理解している場合、これは outputb37a4f2cになります。これは IETF Docu の例です。プラットフォーム固有のエンディアンのオープンウォーターの危険性をスレッド化しているため、ここでは非常に注意してください。0n3011137324 は確かに 0xb37a4f2c ですが、Intel アーキテクチャなどのリトルエンディアン マシンでのみ使用できます。&result[0]to のキャストを再解釈unsigned char*し、(符号なし) int の配列ではなく、バイトの配列として処理する方がよいでしょう。

于 2012-08-16T12:12:40.123 に答える