如何在GCP上使用Python实现Tink的确定性AEAD信封加密?
Python实现GCP KMS + Tink确定性AEAD信封加密
前置准备
- 安装依赖包:
pip install tink google-cloud-kms - 确保环境已配置GCP认证(比如通过
gcloud auth application-default login或服务账号密钥文件) - 在GCP KMS中创建好密钥环和对称加密密钥(作为KEK),记录密钥资源路径(格式如
projects/[PROJECT_ID]/locations/[LOCATION]/keyRings/[KEY_RING]/cryptoKeys/[CRYPTO_KEY])
完整代码示例
import tink from tink import daead from google.cloud import kms_v1 # 初始化Tink的确定性AEAD模块 daead.register() def generate_dek() -> bytes: """生成数据加密密钥(DEK),使用Tink的AES-SIV确定性AEAD模板""" key_template = daead.deterministic_aead_key_templates.AES256_SIV keyset_handle = tink.new_keyset_handle(key_template) # 将DEK序列化为二进制格式 return keyset_handle.write_to_bytes() def encrypt_dek_with_kms(kms_client: kms_v1.KeyManagementServiceClient, kek_path: str, dek: bytes) -> bytes: """使用GCP KMS中的KEK加密DEK""" encrypt_response = kms_client.encrypt( request={"name": kek_path, "plaintext": dek} ) return encrypt_response.ciphertext def decrypt_dek_with_kms(kms_client: kms_v1.KeyManagementServiceClient, kek_path: str, encrypted_dek: bytes) -> bytes: """使用GCP KMS中的KEK解密DEK""" decrypt_response = kms_client.decrypt( request={"name": kek_path, "ciphertext": encrypted_dek} ) return decrypt_response.plaintext def encrypt_data(dek_plaintext: bytes, data: bytes) -> bytes: """使用确定性AEAD加密数据""" # 从DEK明文初始化确定性AEAD实例 keyset_handle = tink.read_keyset_handle_from_bytes(dek_plaintext) daead_primitive = keyset_handle.primitive(daead.DeterministicAead) # 加密数据,可传入关联数据作为第二个参数,示例中为空 ciphertext = daead_primitive.encrypt_deterministically(data, b"") return ciphertext def decrypt_data(encrypted_dek: bytes, kek_path: str, ciphertext: bytes) -> bytes: """解密流程:先解密DEK,再用确定性AEAD解密数据""" kms_client = kms_v1.KeyManagementServiceClient() # 解密DEK dek_plaintext = decrypt_dek_with_kms(kms_client, kek_path, encrypted_dek) # 初始化确定性AEAD实例 keyset_handle = tink.read_keyset_handle_from_bytes(dek_plaintext) daead_primitive = keyset_handle.primitive(daead.DeterministicAead) # 解密数据,需与加密时的关联数据一致 plaintext = daead_primitive.decrypt_deterministically(ciphertext, b"") return plaintext if __name__ == "__main__": # 替换为你的GCP KMS密钥路径 KEK_PATH = "projects/your-project-id/locations/us-central1/keyRings/your-keyring/cryptoKeys/your-kek" # 加密流程示例 kms_client = kms_v1.KeyManagementServiceClient() dek_plaintext = generate_dek() encrypted_dek = encrypt_dek_with_kms(kms_client, KEK_PATH, dek_plaintext) original_data = b"your-sensitive-data-here" ciphertext = encrypt_data(dek_plaintext, original_data) print(f"加密后的DEK: {encrypted_dek.hex()}") print(f"密文: {ciphertext.hex()}") # 解密流程示例 decrypted_data = decrypt_data(encrypted_dek, KEK_PATH, ciphertext) print(f"解密后的数据: {decrypted_data.decode('utf-8')}")
关键说明
- 确定性AEAD选择:示例使用
AES256_SIV模板,这是Tink推荐的确定性AEAD算法,支持关联数据绑定,安全性符合行业标准。 - 信封加密核心流程:
- 生成一次性DEK(仅在内存中存在明文,不落地存储)
- 用GCP KMS的KEK加密DEK,加密后的DEK可与密文一同持久化
- 使用DEK初始化的确定性AEAD实例加密原始数据
- 解密时先通过KMS还原DEK明文,再用其解密密文
- 安全注意事项:
- 严格限制GCP KMS密钥的访问权限,仅授权必要服务账号
- 关联数据(AD)可用于绑定密文的上下文场景,实际使用中可按需添加
- DEK明文仅在内存中临时存在,避免日志或内存dump泄露
内容的提问来源于stack exchange,提问作者Balázs Tóth
相关产品推荐
相关产品推荐

