AES-CTR HMAC 串流 AEAD

本文件正式定義 AES-CTR HMAC Streaming 金鑰 (以 proto 格式編碼為 type.googleapis.com/google.crypto.tink.AesCtrHmacStreamingKey) 所代表的數學函式。

這項加密機制大致以 [HRRV15]1 為基礎。如要分析安全性,請參閱 [HS20]2。請注意,Tink 跨語言測試包含 aes_ctr_hmac_streaming_key_test.py 測試,其中包含 test_manually_created_test_vector,並提供完整的操作說明,說明如何取得密文。

鍵和參數

金鑰會以以下部分說明 (本文件中的所有大小皆以位元組為單位):

  • \(\mathrm{InitialKeyMaterial}\),位元組字串:初始金鑰素材。
  • \(\mathrm{CiphertextSegmentSize} \in \{1, 2, \ldots, 2^{31}-1\}\)。
  • \(\mathrm{DerivedKeySize} \in \{16, 32\}\)。
  • \(\mathrm{HkdfHashType} \in \{\mathrm{SHA1}, \mathrm{SHA256}, \mathrm{SHA512}\}\)。
  • \(\mathrm{HmacHashType} \in \{\mathrm{SHA1}, \mathrm{SHA256}, \mathrm{SHA512}\}\)。
  • \(\mathrm{HmacTagSize} \in \mathbb{N}\)。

有效的鍵還必須符合下列屬性:

  • \(\mathrm{len}(\mathrm{InitialKeyMaterial}) \geq \mathrm{DerivedKeySize}\)。
  • 如果 \(\mathrm{HmacHashType} = \mathrm{SHA1}\) ,則 \(\mathrm{HmacTagSize} \in \{10, \ldots, 20\}\)。
  • 如果 \(\mathrm{HmacHashType} = \mathrm{SHA256}\) ,則 \(\mathrm{HmacTagSize} \in \{10, \ldots, 32\}\)。
  • 如果 \(\mathrm{HmacHashType} = \mathrm{SHA512}\) ,則 \(\mathrm{HmacTagSize} \in \{10, \ldots, 64\}\)。
  • \(\mathrm{CiphertextSegmentSize} > \mathrm{DerivedKeySize} + \mathrm{HmacTagSize} + 8\) (等同於\(\mathrm{len}(\mathrm{Header}) + \mathrm{HmacTagSize}\) ,詳情請參閱後文)。

不符合上述任何屬性的鍵都會遭到 Tink 拒絕 (無論是在剖析鍵時,還是在建立對應的基礎類型時)。

加密功能

如要加密含有相關資料的訊息 \(\mathrm{Msg}\) \(\mathrm{AssociatedData}\),我們會建立標頭、將訊息分割為多個區段、加密每個區段,然後將這些區段連結在一起。我們會在下文中說明這些步驟。

建立標頭

如要建立標頭,我們會先挑選長度為 \(\mathrm{DerivedKeySize}\)的統一隨機字串 \(\mathrm{Salt}\)。接下來,我們會隨機挑選長度為 7 的字串\(\mathrm{NoncePrefix}\) 。

接著,我們會設定\(\mathrm{Header} := \mathrm{len}(\mathrm{Header}) \| \mathrm{Salt} \| \mathrm{NoncePrefix}\),其中標頭長度會編碼為單一位元組。我們注意到\(\mathrm{len}(\mathrm{Header}) \in \{24, 40\}\)。

接下來,我們會使用 HKDF3 搭配雜湊函式 \(\mathrm{HkdfHashType}\),為此訊息計算長度為\(\mathrm{DerivedKeySize} + 32\) 的金鑰素材:\(k := \mathrm{HKDF}(\mathrm{InitialKeyMaterial}, \mathrm{Salt}, \mathrm{AssociatedData})\)。這些輸入內容會用於\(\mathrm{HKDF}\)的對應輸入內容: \(\mathrm{InitialKeyMaterial}\) 是 \(\mathrm{ikm}\)、\(\mathrm{Salt}\) 是鹽,而\(\mathrm{AssociatedData}\) 會用於 \(\mathrm{info}\)。

字串 \(k\) 隨後會分割成兩個部分 \(k_1 \| k_2 := k\),例如\(\mathrm{len}(k_1) = \mathrm{DerivedKeySize}\) 和 \(\mathrm{len}(k_2) = 32\)。

分割訊息

接著,訊息 \(M\) 會分成以下部分: \(M = M_0 \| M_1 \| \cdots \| M_{n-1}\)。

長度會選擇為滿足下列條件:

  • \(\mathrm{len}(M_0) \in \{0,\ldots, \mathrm{CiphertextSegmentSize} - \mathrm{len}(\mathrm{Header}) - \mathrm{HmacTagSize}\}\)。
  • 如果為 \(n > 1\),則為 \(\mathrm{len}(M_1), \ldots, \mathrm{len}(M_{n-1}) \in \{1,\ldots, \mathrm{CiphertextSegmentSize} - \mathrm{HmacTagSize}\}\)。
  • 如果為 \(n > 1\),則 \(M_{0}, \ldots, M_{n-2}\) 必須根據上述限制設為最大長度。

在這個分割作業中, \(n\) 最多可為 \(2^{32}\)。否則加密作業會失敗。

加密區塊

如要加密區段 \(M_i\),我們會先計算\(\mathrm{IV}_i := \mathrm{NoncePrefix} \| \mathrm{i} \| b \| 0x00000000\),並使用大端編碼方式將 \(\mathrm{i}\) 編碼為 4 個位元組,如果 $i < n-1$,則將位元組 $b$ 設為 0x00,否則設為 0x01

接著,我們會使用 AES CTR 金鑰 \(k_1\)和初始化向量\(\mathrm{IV}_i\)加密資料。 \(M_i\) 換句話說,AES 叫用的輸入內容為\(\mathrm{IV}_i, \mathrm{IV}_i + 1, \mathrm{IV}_i + 2, \ldots\),其中 \(\mathrm{IV}_i\) 會解讀為大端整數。這會產生 \(C'_i\)。

我們會使用 HMAC 計算標記,並使用 \(\mathrm{HmacHashType}\) 提供的雜湊函式,以及在連接\(\mathrm{IV}_i \| C'_i\)時使用金鑰 \(k_2\) 。

接著,我們將密文與標記連接,取得 \(C_i\)。

連結區段

最後,所有區段會串連為\(\mathrm{Header} \| C_0 \| \cdots \| C_{n-1}\),也就是最終的密文。

解密函式

解密只需將加密內容反轉即可。我們會使用標頭取得 Nonce,並個別解密每個密文區段。

API 可能會 (通常會) 允許隨機存取,或在未檢查檔案結尾的情況下存取檔案開頭。這是有意為之,因為您可以從 \(C_i\)解密 \(M_i\) ,而無須解密所有先前和剩餘的密文區塊。

不過,API 應謹慎處理,避免使用者將檔案結尾和解密錯誤搞混:在兩種情況下,API 都可能會傳回錯誤,而忽略差異可能導致對手有效截斷檔案。

金鑰的序列化和剖析

如要以「Tink Proto」格式序列化金鑰,我們會先以明顯的方式將參數對應至 aes_ctr_hmac_streaming.proto 中提供的原始檔。version 欄位必須設為 0。接著,我們會使用一般 Proto 序列化功能將其序列化,並將產生的字串嵌入 KeyData Proto 欄位的值中。我們將 type_url 欄位設為 type.googleapis.com/google.crypto.tink.AesCtrHmacStreamingKey。接著,我們將 key_material_type 設為 SYMMETRIC,並將其嵌入鍵組中。我們通常會將 output_prefix_type 設為 RAW。例外狀況是,如果鍵是使用 output_prefix_type 的不同值集進行剖析,Tink 可能會寫入 RAW 或先前的值。

如要剖析鍵,我們會反向執行上述程序 (以剖析 Protobuf 的一般方式)。系統會忽略欄位 key_material_typeoutput_prefix_type 的值可以忽略,或是可以拒絕 output_prefix_typeRAW 不同的鍵。系統會拒絕 version 與 0 不同的鍵。

參考資料


  1. [HRRV15] Hoang, Reyhanitabar, Rogaway, Vizar. 線上驗證加密功能,以及可抵禦重複使用 Nonce 的濫用行為。CRYPTO 2015。https://eprint.iacr.org/2015/189 

  2. [HS20] Google Tink 程式庫中的串流加密安全性。Hoang, Shen, 2020. https://eprint.iacr.org/2020/1019 

  3. [HKDF] HMAC Extractor-and-Expand Key Derivation Function (HKDF),RFC 5869。https://www.rfc-editor.org/rfc/rfc5869