本文档正式定义了以 proto 格式编码为 type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey
的 AES-GCM-HKDF 流式密钥表示的数学函数。
此加密方式大致基于 HRRV151。对于安全分析,我们参考 HS202。
键和参数
键由以下部分描述(本文档中的所有大小均以字节为单位):
- ,一个字节字符串。
- 。
- 。
- 。
有效键还满足以下属性:
- 。
- (如后所述,此值等于 )。
在解析键或创建相应基元时,如果键不满足上述任何属性,Tink 都会拒绝该键。
加密函数
如需 对包含关联数据的消息进行加密,我们需要创建一个标头,将消息拆分为多个分段,对每个分段进行加密,然后将已加密的分段串联起来。
创建标头
我们选择一个长度为 的均匀随机字符串 ,以及一个长度为 7 的均匀随机字符串 。
然后,我们设置 ,其中标头的长度编码为单个字节。请注意 。
接下来,我们将 HKDF3 与 给出的哈希函数以及输入 、 和 结合使用,输出长度为 。我们将结果称为 。
拆分消息
接下来,消息 会拆分为以下部分: 。
其长度应满足以下条件:
- 。
- 如果 ,则 。
- 如果为 ,则 必须具有上述约束条件的最大长度。
不得超过 。否则,加密将失败。
加密分块
如需对分段 进行加密,我们需要计算 ,其中 是采用大端字节编码的 4 个字节,如果 ,则字节 为 0x00
,否则为 0x01
。
然后,我们 使用 AES-GCM4 进行加密,其中密钥为,初始化矢量为 ,相关数据为空字符串。 是此加密操作的结果(即链接的 AES-GCM 参考文档第 5.2.1.2 节中的 和 的串联)。
串联加密的片段
最后,将所有分段串联为 ,即最终的密文。
解密
解密会对加密进行反向操作。我们使用标头获取,并单独解密每个密文段。
API 可能会(通常也确实会)允许随机访问,或者允许访问文件开头,而无需检查文件结尾。这是有意为之,因为可以从 解密 ,而无需解密所有之前和剩余的密文块。
不过,API 应注意不要让用户混淆文件结束错误和解密错误:在上述两种情况下,API 都可能必须返回错误,而忽略这种差异可能会导致攻击者能够有效地截断文件。
键的序列化和解析
如需以“Tink Proto”格式序列化密钥,我们首先会以显而易见的方式将参数映射到 aes_gcm_hkdf_streaming.proto 中给出的 proto。需要将 version
字段设置为 0。然后,我们使用常规 Proto 序列化进行序列化,并将生成的字符串嵌入 KeyData Proto 字段的值中。我们将 type_url
字段设置为 type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey
。然后,我们将 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 的密钥。
已知问题
上述加密函数的实现预计不会支持分叉。请参阅分支安全。
参考
-
Hoang, Reyhanitabar, Rogaway, Vizar, 2015. 在线身份验证加密及其 Nonce 重复使用滥用防范。CRYPTO 2015。 https://eprint.iacr.org/2015/189 ↩
-
Hoang, Shen, 2020. Google Tink 库中的流式加密安全性。https://eprint.iacr.org/2020/1019 ↩
-
RFC 5869。基于 HMAC 的提取和展开密钥派生函数 (HKDF)。 https://www.rfc-editor.org/rfc/rfc5869 ↩
-
NIST SP 800-38D。对分块加密算法操作模式的建议:伽罗瓦/计数器模式 (GCM) 和 GMAC。https://csrc.nist.gov/pubs/sp/800/38/d/final ↩