AES-CTR HMAC 流式传输 AEAD

本文档正式定义了由 AES-CTR HMAC 流式传输密钥(以 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{AssociatedData}\)的消息, \(\mathrm{Msg}\) 需要创建一个标头,将消息拆分为多个片段,对每个片段进行加密,然后串联这些片段。下文中介绍了这些步骤。

创建标头

如需创建标头,我们首先选择一个长度为 \(\mathrm{Salt}\)的统一随机字符串 \(\mathrm{DerivedKeySize}\)。接下来,我们选择一个长度为 7 的统一随机字符串\(\mathrm{NoncePrefix}\) 。

然后设置\(\mathrm{Header} := \mathrm{len}(\mathrm{Header}) \| \mathrm{Salt} \| \mathrm{NoncePrefix}\),其中标头的长度编码为单个字节。我们注意到,\(\mathrm{len}(\mathrm{Header}) \in \{24, 40\}\).

接下来,我们结合使用 HKDF3 和哈希函数 \(\mathrm{HkdfHashType}\),针对此消息\(k := \mathrm{HKDF}(\mathrm{InitialKeyMaterial}, \mathrm{Salt}, \mathrm{AssociatedData})\)计算长度为\(\mathrm{DerivedKeySize} + 32\) 的密钥材料。输入用于\(\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\),其中使用 big-endian 编码以 4 个字节编码 \(\mathrm{i}\) ,如果 $i < n-1$,则将字节 $b$ 设置为 0x00,否则将字节 $b$ 设置为 0x000x01

然后,我们 \(M_i\) 使用 AES CTR 密钥 \(k_1\)和初始化矢量\(\mathrm{IV}_i\)进行加密。换言之,AES 调用的输入为\(\mathrm{IV}_i, \mathrm{IV}_i + 1, \mathrm{IV}_i + 2, \ldots\),其中 \(\mathrm{IV}_i\) 被解释为大端字节序整数。这将生成 \(C'_i\)。

我们使用 HMAC 通过串联\(\mathrm{IV}_i \| C'_i\)通过 \(\mathrm{HmacHashType}\) 给定的哈希函数和密钥 \(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 中提供的 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 或先前的值。

为了解析键,我们会反向执行上述过程(以解析 proto 时的常规方式)。系统会忽略“key_material_type”字段。可以忽略 output_prefix_type 的值,或者拒绝 output_prefix_typeRAW 不同的键。version 不为 0 的键会被拒绝。

参考


  1. [HRRV15] Hoang、Reyhanitabar、Rogaway、Vizar。在线身份验证加密及其防 Nonce 重用 (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 的提取和扩展密钥派生函数 (HKDF),RFC 5869。https://www.rfc-editor.org/rfc/rfc5869