為什麼閃電網路上傳輸消息的長度是加密的?
從 BOLT 08 中我們可以看到,每條消息都是通過以下方式發送的:
2 byte: length 16 byte: MAC [length] byte: Encrypted message 16 byte: MAC
實際上,這些消息將通過 Internet 上的 TCP/IP 發送。ip 標頭指定正在發送的數據包的長度。如果我們提取長度並減去標頭的 34 字節加上兩個 MAC,我們將知道消息有多長。
總是發送一個 2^16 字節的 ip 包並用垃圾數據填充其餘部分的想法是什麼?如果是,為什麼沒有在 BOLT 中指定?如果不是:為什麼還要加密長度?
我假設攻擊者能夠跟踪閃電埠上的所有 tcp/ip 包,並且至少能夠推斷出正在發送的消息,即使消息本身是安全的。
假設確實可以推斷出消息長度,那不能與 MAC 一起使用來重建該消息的會話密鑰嗎?
TCP 和其他基於流的協議在應用程序級消息和 IP 數據包之間沒有一對一的關聯。如果您呼叫
send()
3 次,可能會導致通過線路發送單個 IP 數據包(例如,由於預設啟用的 Nagle 算法),它可能會作為 3 個數據包單獨發送,正如您對面向數據包的協議所期望的那樣像 UDP,或者消息可能最終被分成幾個數據包,因為 IP 層有一個 MTU。它通常在應用層是不受您控制的。因此,您不能依靠從 IP 標頭中讀取長度來告訴您消息的長度。您需要將長度編碼到數據流中,並將從流中傳入的數據重建為協議所理解的單個消息。
在 BOLT#8 規範中單獨對長度進行編碼的原因是,每條消息都必須作為單個操作進行解密,因為每次解密都必須增加 ChaChaPoly 密碼中使用的計數器。在對加密的有效負載呼叫解密函式之前,您需要知道消息的確切長度。
在 BOLT#8 協議中,您發送加密消息 + MAC 的確切長度,不添加任何填充。接收者應首先顯式呼叫
recv(buffer, 18, ...)
,解密結果以獲得msg_len
,然後呼叫recv(buffer, msg_len, ...)
以檢索加密消息,然後可以將其完整解密。recv
也可能返回比請求更少的字節,因此在這兩種情況下,都recv
必須檢查結果,如果讀取的長度小於預期長度,recv
則應使用剩餘的預期長度再次呼叫。