本文档正式定义了由 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{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 个字节,并将字节 $b$ 设置为 $i < n-1$ 时为 0x00
,否则为 0x01
。
然后,我们 \(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{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 中给出的 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_type
与 RAW
不同的键。系统会拒绝 version
不同于 0 的键。
参考
-
[HRRV15] Hoang、Reyhanitabar、Rogaway、Vizar。在线身份验证加密及其 Nonce 重复使用滥用行为防范功能。CRYPTO 2015。 https://eprint.iacr.org/2015/189 ↩
-
[HS20] Google Tink 库中的流式加密安全性。 Hoang, Shen, 2020. https://eprint.iacr.org/2020/1019 ↩
-
[HKDF] 基于 HMAC 的提取和展开密钥派生函数 (HKDF),RFC 5869。https://www.rfc-editor.org/rfc/rfc5869 ↩