本主题说明了 BigQuery 中 AEAD 加密背后的概念。 如需了解 BigQuery 支持的各种 AEAD 加密函数,请参阅 AEAD 加密函数。
AEAD 加密的用途
BigQuery 利用静态加密来确保数据的安全。BigQuery 还支持客户管理的加密密钥 (CMEK),可让您使用特定加密密钥对表进行加密。但是,在某些情况下,您可能希望对表中的个别值进行加密。
例如,您希望将自己的所有客户数据都保存在一个公用表中,并使用不同的密钥来加密每个客户的数据。若您有数据分布在多个表中,可能会希望能够对这些表执行“密钥删除”。“密钥删除”(或称“密钥销毁”)是一个删除加密密钥以显示使用该密钥加密的任何不可读数据的过程。
AEAD 加密函数可让您创建包含加密和解密密钥的密钥集、使用这些密钥对表中的个别值进行加密和解密,以及轮替密钥集内的密钥。
密钥集
密钥集是一组加密密钥,由一个主加密密钥和其余的辅助加密密钥(如果有的话)组成。无论是启用的、停用的还是已销毁的密钥,每个密钥都是对一个加密或解密算法的编码。对于非销毁密钥,则是对自身的字节编码。主加密密钥决定了输入明文的加密方式,且永不可停用。 辅助加密密钥只能用于解密,且可启用或停用。密钥集可用于解密使用该密钥集加密的任何数据。
密钥集在 BigQuery 中采用 BYTES
形式的序列化 google.crypto.tink.Keyset 协议缓冲区表示法。
示例
以下示例以 JSON 字符串形式表示包含三个密钥的 AEAD 密钥集。
primary_key_id: 569259624
key {
key_data {
type_url: "type.googleapis.com/google.crypto.tink.AesGcmKey"
value: ",&\264kh\377\306\217\371\233E<\0350A4\023B-pd\203\277\240\371\212^\210bf\347\256"
key_material_type: SYMMETRIC
}
status: ENABLED
key_id: 569259624
output_prefix_type: TINK
}
key {
key_data {
type_url: "type.googleapis.com/google.crypto.tink.AesGcmKey"
value: "\374\336+.\333\245k\364\010`\037\267!\376\233\\3\215\020\356B\236\240O\256U\021\266\217\277\217\271"
key_material_type: SYMMETRIC
}
status: DISABLED
key_id: 852264701
output_prefix_type: TINK
}
key {
status: DESTROYED
key_id: 237910588
output_prefix_type: TINK
}
在上面的示例中,主加密密钥是 JSON 字符串中列出的第一个密钥,其 ID 为 569259624
。有两个辅助加密密钥:一个是 ID 为 852264701
的已停用密钥,另一个是 ID 为 237910588
的已销毁密钥。当 AEAD 加密函数使用此密钥集进行加密时,生成的密文会对主加密密钥 ID 569259624
进行编码。
当 AEAD 函数使用此密钥集进行解密时,该函数会根据密文中编码的密钥 ID 选择适当的密钥进行解密。在上面的示例中,尝试使用 ID 为 852264701
或 237910588
的密钥进行解密将会导致出错,因为 ID 为 852264701
的密钥已停用且 ID 为 237910588
的密钥已销毁。将 ID 为 852264701
的密钥恢复为启用状态后,该密钥才可用于解密。
密钥类型用于确定与该密钥搭配使用的加密模式。
由于使用 OpenSSL 提供的伪随机数生成器选择的初始化矢量 (IV) 各不相同,因此若使用同一密钥集对明文进行多次加密,通常每次返回的密文值都不相同。
高级加密标准 (AES)
AEAD 加密函数使用高级加密标准 (AES) 加密。AES 加密接受明文和加密密钥作为输入,并会返回加密的字节序列作为输出。随后,便可使用加密时所用的同一密钥来解密此字节序列。AES 使用的块大小为 16 个字节,这意味着明文会被视为一组 16 个字节的块序列。密文将包含 Tink 特定的前缀,以指示用于执行加密的密钥。AES 加密支持多种块加密模式。
块加密模式
AEAD 加密函数支持两种块加密模式:GCM 和 CBC。
GCM
伽罗瓦/计数器模式 (GCM) 是一种适用于 AES 加密的模式。该函数按顺序对块进行编号,然后将此块编号与初始化矢量 (IV) 组合在一起。初始化矢量是一个随机值或伪随机值,构成了明文数据随机化的基础。接下来,函数会使用 AES 对块编号和 IV 的组合进行加密。然后,函数会对加密结果和明文执行按位逻辑异或 (XOR) 运算以生成密文。GCM 模式使用 128 或 256 位的加密密钥。
CBC 模式
在 CBC 模式中,通过将每个明文块与前一个密文块进行异或运算将各个块“链接”在一起,然后再进行加密。CBC 模式使用 128 位、192 位或 256 位的加密密钥。CBC 使用一个 16 个字节的初始化矢量作为初始块,并将此初始块与第一个明文块进行异或运算。
CBC 模式不是加密意义上的 AEAD 方案,因为它不提供数据完整性;换句话说,对加密数据的恶意修改不会被检测,这些恶意修改也会破坏数据机密性。因此,除非需要旧版,否则不建议使用 CBC。
附加数据
AEAD 加密函数支持使用 additional_data
参数,该参数也称为关联数据 (AD) 或附加身份验证数据。与密钥集不同,生成的密文无法仅使用此附加数据进行解密。此附加数据可保证加密数据的真实性和完整性,但不能保证其私密性。
例如,在为特定客户加密数据时,additional_data
可以作为 CAST(customer_id AS STRING)
的输出。这可确保在解密数据时,数据先前已使用预期的 customer_id
进行加密。解密时需要使用相同的 additional_data
值。如需了解详情,请参阅 RFC 5116。
解密
AEAD.ENCRYPT
的输出是密文 BYTES
。AEAD.DECRYPT_STRING
或 AEAD.DECRYPT_BYTES
函数可以对此密文进行解密。这些函数必须使用包含加密所用密钥的密钥集。该密钥必须处于 'ENABLED'
状态。这些函数还必须使用加密时所使用的相同 additional_data
。
当使用密钥集进行解密时,系统会根据密文中编码的密钥 ID 选择相应的密钥进行解密。
AEAD.DECRYPT_STRING
的输出是明文 STRING,而 AEAD.DECRYPT_BYTES
的输出是明文 BYTES
。AEAD.DECRYPT_STRING
可以解密对 STRING 值进行编码的密文;AEAD.DECRYPT_BYTES
可以解密对 BYTES
值进行编码的密文。使用其中一个函数来解密对错误数据类型进行编码的密文(例如,使用 AEAD.DECRYPT_STRING
来解密对 BYTES
值进行编码的密文)会导致不确定的行为,并且可能会导致错误。
密钥轮替
轮替加密密钥主要是为了减少使用任何特定密钥加密数据的数据量,这样一来,即使某个密钥被破解,攻击者也只能访问到较少的数据。
密钥集轮替涉及以下操作:
- 在每个密钥集内创建新的主加密密钥。
- 对所有已加密数据进行解密,然后再重新加密。
使用 KEYS.ROTATE_KEYSET
函数执行第一步操作,方法是向密钥集添加新的主加密密钥,并将旧的主加密密钥变成辅助加密密钥。