本页将介绍 Tink 的密钥和基元输出的传输格式。本文档面向希望向 Tink 添加其他语言的密码学者,以及希望使用电汇兼容模式的其他高级加密库的维护者。它不面向一般受众。
密钥集序列化
Tink 使用 Google protobuf 来序列化其密钥集。
- 二进制序列化密钥集是在 tink.proto 中定义的序列化 Keyset proto。键的 KeyData 值属性是相应密钥类型的序列化 proto。
- JSON 序列化密钥集是以 JSON 格式序列化的密钥集 proto。 请注意,KeyData 值仍然是二进制序列化 proto。
- 加密密钥集是在 tink.proto 中定义的序列化 EncryptedKeyst proto。它包含一个加密的二进制序列化密钥集,以及可选的一些未加密的 KeysetInfo 元数据。
Tink 输出前缀
大多数 Tink 基元都支持 5 字节的输出前缀,其中包含:
- 1 字节版本:
0x01
- 4 个字节的密钥提示:这是所用密钥的密钥 ID。
部分旧版密钥可能也支持版本字节 0x00
。
请注意,此前缀未经过身份验证,不能可靠地出于安全考虑。Tink 会将其用作提示来加快解密或验证速度。
AEAD
通常,Tink 会将 AEAD 密文的格式设置为:
prefix || IV || ciphertext || tag
除非相应 RFC 中另有规定。prefix
为空或 5 字节 Tink 输出前缀。
AES-CTR-HMAC
对于 AES-CTR-HMAC,Tink 使用相关数据 (AD) 计算 MAC,如下所示:
AD || IV || ciphertext || bitlen(AD)
其中 bitlen(AD)
是 AD 的长度(以位为单位),表示为 64 位大端序无符号整数。此 HMAC 方案遵循 Mcgrew 的 AES-CBC-HMAC 草稿。
确定性 AEAD
Tink 针对 AES-SIV 实现了 RFC 5297,并将合成初始化矢量 (SIV) 置于密文的开头。基元可以添加一个 5 字节的 Tink 输出前缀。
虽然 RFC 5297 支持关联数据列表,但 Tink 仅支持关联数据列表,这对应于 RFC 5297 中包含一个元素的列表。关联的空数据是指包含一个空元素的列表,而不是一个空列表。
流式 AEAD
请参阅 AES-CTR HMAC 和 AES-GCM-HKDF。
信封加密
信封加密使用 Tink 的 AEAD 基元通过数据加密密钥 DEK
来加密数据。加密的工作原理如下:
- 系统会使用给定的密钥模板(或密钥参数)生成新的
DEK
。 DEK
已序列化为字节字符串。密钥类型 proto 的协议缓冲区序列化的序列化格式。例如,这是在 aes_gcm.proto 中为 AES GCM 密钥类型的 DEK 定义的序列化AesGcmKey
协议缓冲区消息。如需了解如何对协议缓冲区进行序列化,请参阅协议缓冲区序列化。- 序列化的
DEK
由外部提供程序(例如 GCP)加密成encrypted DEK
。 DEK
用于将包含关联数据的明文加密到ciphertext
中。因此,ciphertext
与DEK
对应的 AEAD 基元的格式完全相同。
信封加密的输出格式如下:
encrypted DEK length || encrypted DEK || ciphertext
encrypted DEK length
是 4 个字节,将 encrypted DEK
的长度存储为 32 位大端整数。
MAC
Tink 遵循相应的 RFC。原语可以向标记添加 5 字节的 Tink 输出前缀。
PRF 集
Tink 遵循相应的 RFC。请注意,对于 PRF 密钥,密钥类型与同一算法的 MAC 密钥类型不同,因为它不包含输出长度。PRF 设置键从不添加 Tink 输出前缀。这样可以确保输出实际上是 PRF。
混合加密
Tink 混合加密的常规传输格式如下:
prefix || encapsulated_key || encrypted_data
prefix
为空或 5 字节 Tink 输出前缀。每种键类型都包含有关要解析的字节数以及如何从 encapsulated_key
解析这些字节的信息。
HPKE(混合公钥加密)
Tink 遵循 RFC 9180 中定义的 HPKE 标准。HPKE 密码套件包含以下三个基元。
- 密钥封装机制 (KEM)
- 密钥推导函数 (KDF)
- 使用关联数据的身份验证加密 (AEAD)
HPKE 标准在 RFC 9180 第 10 节中未定义通用传输格式。Tink 的 HPKE 实现使用以下 encapsulated_key
和 encrypted_data
值。
encapsulated_key
- 发送者的序列化公钥
- 在 RFC 9180 第 4.1 节中定义为
enc
- 格式取决于所使用的具体 HPKE KEM
encrypted_data
- 加密文本和标记(即
ciphertext || tag
(不含 IV) - 在 RFC 9180 第 4 节中定义为
ct
- 格式取决于所使用的具体 HPKE AEAD
- 加密文本和标记(即
X25519 基于 Diffie-Hellman 的 KEM
对于 X25519 DHKEM,值 enc
是发送者的 32 字节 Diffie-Hellman 公钥。
ECIES-AEAD-HKDF
对于 Tink 的 ECIES-AEAD-HKDF 实现,encapsulated_key
是密钥封装机制 (KEM) 的输出,encrypted_data
是数据封装机制 (DEM) 的输出。
肯尼亚先令
根据密钥类型,Tink 按照 RFC 8422/ANSI.X9-62.2005
编码标准使用经过压缩和未压缩的椭圆曲线点。对于未压缩的点,字节 0x04
后跟 x
和 y
坐标(作为固定大小的整数)。对于压缩坐标,使用字节 0x02
或 0x03
,以及作为固定大小整数的 x
坐标。对于 X25519
,则使用 RFC 7748 定义(x
坐标为固定大小的整数)。
德国马克
对于 encrypted_data
,Tink 使用与 AEAD 相同的格式。这包括指定 IV。
密钥派生
首先计算共享点的 x 坐标 x_ss
。然后,AEAD 的密钥设置为:
HKDF(ikm = encapsulated_key || x_ss, salt = salt_of_key, info = context_info, length = dem_key_size)
其中 encapsulated_key
是以字节表示的完整 KEM 输出。
数字签名
Tink 遵循相应的 RFC。原语可以向生成的标记添加 5 字节的 Tink 输出前缀。
ECDSA
根据密钥中的 EcdsaSignatureEncoding 字段,ECDSA 签名的格式为 IEEE P1363
或 ASN.1 DER
。
IEEE P1363
签名的格式为 r || s
,其中 r
和 s
填充了零,且大小(以字节为单位)与曲线的顺序相同。例如,对于 NIST P-256
曲线,r
和 s
将填充零来补齐 32 个字节。
DER 签名使用 ASN.1
进行编码:
ECDSA-Sig-Value :: = SEQUENCE { r INTEGER, s INTEGER }
具体来说,编码为:
0x30 || totalLength || 0x02 || r's length || r || 0x02 || s's length || s
Tink 遵循了签名验证的最佳实践,只接受 DER 编码的 ECDSA 签名(备用的 BER 编码签名无效)。
这有助于防止签名可塑性攻击,此类攻击通常会影响加密货币系统。