2012-05-13 90 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*,然後將其作爲一個字節數組來處理,而不是一組(無符號)整數。