用於 UDP 數據包流的 AES + CBC 加密
我正在開發一個基於 UDP 的應用程序,我需要發送一個數據包流。可以想像,數據包可能會失去或損壞。我需要確保這些數據包的內容是加密的,並且我還需要能夠證明我收到的數據包是正確的。
最後,由於性能在我的應用程序中至關重要,因此我希望盡可能減少加密成本。通常,數據包相對較小,因此即使是幾個塊也可能會產生相對較大的成本。
我以前沒有可靠的密碼學經驗,所以我認為最好不要相信自己。
這是我到目前為止使用的策略(我的應用程序還遠未發布,因此必須或多或少地完全更改它不會有太大問題)。
首先,數據包的大小是固定的,通常是 AES 塊大小的倍數。我不需要任何填充,因為消息的長度不可變。
我使用一個共享密鑰(顯然)和兩個固定的 IV,每個端點使用兩者之一來加密其消息。我在 CBC 模式下使用 AES。
由於顯然使用固定的 IV 會導致一大堆安全漏洞,因此我需要讓我的第一個塊以統一隨機的方式變化:這將充當下一個塊的 IV。
因此,我在數據包的開頭添加了一個塊。其內容如下:
- 前四個字節:目前時間戳(以秒為單位)
- 接下來的 12 個字節:零
- 我計算消息的 sha256 散列(32 字節)
- 我將時間戳+零塊與雜湊的前半部分進行異或
- 我將結果與雜湊的後半部分進行異或
當我在另一個端點上收到數據包時,我使用密鑰和遠端 iv 對其進行解密。
我計算消息的 sha256 雜湊(沒有第一個塊),異或前半部分和後半部分。
我對第一個塊的散列過程的結果進行異或。
如果我得到一個不超過幾秒前的時間戳和 12 個字節的零,那麼數據包是正確的。
如果數據包不正確,我就丟棄它,就像我沒有收到它一樣。沒有答案被發回。
這個程序有什麼缺陷?
加密的“有趣”部分在這裡:
因此,我在數據包的開頭添加了一個塊。其內容如下:
- 前四個字節:目前時間戳(以秒為單位)
- 接下來的 12 個字節:零
- 我計算消息的 sha256 散列(32 字節)
- 我將時間戳+零塊與雜湊的前半部分進行異或
- 我將結果與雜湊的後半部分進行異或
由於 XOR 是可交換的和關聯的,因此順序無關緊要,您正在使用來自定義為 SHA-256 兩半的 XOR 的函式的散列對零填充時間戳進行 XOR。
這應該敲響一些警鐘。SHA-256 的長度為 256 位是有原因的,那是因為雜湊的抗碰撞性僅 $ n/2 $ 位。通過將散列的長度減半(您可以通過截斷同樣強烈地做到這一點),您可以將其抗碰撞性降低到 64 位,這被認為不夠強大。
現在,如果您只依賴散列函式的原像或第二原像抗性,就可以了。然而,加密雜湊作為 MAC 的安全性依賴於它的抗衝突性。
相反,您可以只使用普通的 MAC(如 HMAC),最好在 encrypt-then-MAC中。或者更好的是,一種經過身份驗證的加密模式(如 GCM)。
然而,這並不能解決 IV 的缺乏問題。如果您繼續使用 CBC,您可以為此目的生成一個隨機數,如果必須,無需花哨。基於 CTR 的模式,如 GCM,需要一個唯一的 nonce,並且不能以這種方式從重複中恢復。
您的選擇,從最推薦到最不推薦是:
- 不要推出自己的協議,而是使用 (D)TLS。
- 如果您必須使用自己的協議,請使用經過身份驗證的加密模式。
- 如果不能,至少使用標準加密和 MAC。