I want to use client-side encryption with a cloud provider

First, the client generates a Data Encryption Key (DEK). Second, data is encrypted using the DEK. Third, the DEK is encrypted by a Key Encryption Key (KEK) that is stored in a cloud provider's Key Management System (KMS). You need to provide Tink with the following:

Tink supports this in two ways. The simpler (but less flexible) way uses Tink's KMS envelope encryption. When you encrypt data, Tink automatically creates a new DEK and stores it as part of the ciphertext, so you don't need to handle the DEK yourself. The ciphertext will be a bit longer (because it includes the encrypted DEK). Every time you encrypt or decrypt, Tink makes an RPC to the KMS.

The other way allows you to use streaming AEAD and/or avoid making an RPC per encrypt or decrypt. You should use encrypted keysets for this, see Key Management.

KMS envelope encryption

When you encrypt data using KMS envelope encryption, Tink generates a new DEK and encrypts your data with it. It then calls your KMS (using the KEK key URI and the credentials) to encrypt the DEK with the KEK located in the KMS. The ciphertext is then a concatenation of the encrypted DEK and encrypted data.

When you decrypt, Tink will do the reverse. It extracts the encrypted DEK from the ciphertext, and calls the KMS to decrypt the DEK. It then locally decrypts the data using the DEK and outputs the decrypted data.

By using a KMS, your KEK resides safely in the cloud, where you can rotate, deactivate, or destroy it, depending on your needs.

The following examples assume you have already created a KEK in your cloud provider’s KMS and have a key URI and credentials to pass to Tink.


"""A command-line utility for encrypting small files using envelope encryption with GCP."""

from absl import app
from absl import flags
from absl import logging

import tink
from tink import aead
from tink.integration import gcpkms


flags.DEFINE_enum('mode', None, ['encrypt', 'decrypt'],
                  'The operation to perform.')
flags.DEFINE_string('kek_uri', None,
                    'The Cloud KMS URI of the key encryption key.')
flags.DEFINE_string('gcp_credential_path', None,
                    'Path to the GCP credentials JSON file.')
flags.DEFINE_string('input_path', None, 'Path to the input file.')
flags.DEFINE_string('output_path', None, 'Path to the output file.')
flags.DEFINE_string('associated_data', None,
                    'Optional associated data used for the encryption.')

def main(argv):
  del argv  # Unused.

  associated_data = b'' if not FLAGS.associated_data else bytes(
      FLAGS.associated_data, 'utf-8')

  # Initialise Tink
  except tink.TinkError as e:
    logging.error('Error initialising Tink: %s', e)
    return 1

  # Read the GCP credentials and setup client
        FLAGS.kek_uri, FLAGS.gcp_credential_path)
  except tink.TinkError as e:
    logging.error('Error initializing GCP client: %s', e)
    return 1

  # Create envelope AEAD primitive using AES256 GCM for encrypting the data
    template = aead.aead_key_templates.create_kms_envelope_aead_key_template(
    handle = tink.new_keyset_handle(template)
    env_aead = handle.primitive(aead.Aead)
  except tink.TinkError as e:
    logging.error('Error creating primitive: %s', e)
    return 1

  with open(FLAGS.input_path, 'rb') as input_file:
    input_data = input_file.read()
    if FLAGS.mode == 'decrypt':
      output_data = env_aead.decrypt(input_data, associated_data)
    elif FLAGS.mode == 'encrypt':
      output_data = env_aead.encrypt(input_data, associated_data)
          'Error mode not supported. Please choose "encrypt" or "decrypt".')
      return 1

    with open(FLAGS.output_path, 'wb') as output_file:

if __name__ == '__main__':
      'mode', 'kek_uri', 'gcp_credential_path', 'input_path', 'output_path'])


For this example you need both tink-java and the Google Cloud KMS extension tink-java-gcpkms.

package envelopeaead;

import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.crypto.tink.Aead;
import com.google.crypto.tink.KeyTemplates;
import com.google.crypto.tink.KeysetHandle;
import com.google.crypto.tink.aead.AeadConfig;
import com.google.crypto.tink.aead.KmsEnvelopeAeadKeyManager;
import com.google.crypto.tink.integration.gcpkms.GcpKmsClient;
import java.io.File;
import java.io.FileOutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.GeneralSecurityException;
import java.util.Optional;

 * A command-line utility for encrypting small files with envelope encryption.
 * <p>It requires the following arguments:
 * <ul>
 *   <li>mode: Can be "encrypt" or "decrypt" to encrypt/decrypt the input to the output.
 *   <li>kek-uri: Use this Cloud KMS' key as the key-encrypting-key for envelope encryption.
 *   <li>gcp-credential-file: Use this JSON credential file to connect to Cloud KMS.
 *   <li>input-file: Read the input from this file.
 *   <li>output-file: Write the result to this file.
 *   <li>[optional] associated-data: Associated data used for the encryption or decryption.
public final class EnvelopeAeadExample {
  private static final String MODE_ENCRYPT = "encrypt";
  private static final String MODE_DECRYPT = "decrypt";

  public static void main(String[] args) throws Exception {
    if (args.length != 5 && args.length != 6) {
      System.err.printf("Expected 5 or 6 parameters, got %d\n", args.length);
          "Usage: java EnvelopeAeadExample encrypt/decrypt kek-uri gcp-credential-file"
              + " input-file output-file [associated-data]");
    String mode = args[0];
    String kekUri = args[1];
    String gcpCredentialFilename = args[2];
    byte[] input = Files.readAllBytes(Paths.get(args[3]));
    File outputFile = new File(args[4]);
    byte[] associatedData = new byte[0];
    if (args.length == 6) {
      System.out.println("Associated data!");
      associatedData = args[5].getBytes(UTF_8);
    // Initialise Tink: register all AEAD key types with the Tink runtime

    // Read the GCP credentials and set up client
    try {
      GcpKmsClient.register(Optional.of(kekUri), Optional.of(gcpCredentialFilename));
    } catch (GeneralSecurityException ex) {
      System.err.println("Error initializing GCP client: " + ex);

    // Create envelope AEAD primitive using AES256 GCM for encrypting the data
    Aead aead = null;
    try {
      KeysetHandle handle =
              KmsEnvelopeAeadKeyManager.createKeyTemplate(kekUri, KeyTemplates.get("AES256_GCM")));
      aead = handle.getPrimitive(Aead.class);
    } catch (GeneralSecurityException ex) {
      System.err.println("Error creating primitive: %s " + ex);

    // Use the primitive to encrypt/decrypt files.
    if (MODE_ENCRYPT.equals(mode)) {
      byte[] ciphertext = aead.encrypt(input, associatedData);
      try (FileOutputStream stream = new FileOutputStream(outputFile)) {
    } else if (MODE_DECRYPT.equals(mode)) {
      byte[] plaintext = aead.decrypt(input, associatedData);
      try (FileOutputStream stream = new FileOutputStream(outputFile)) {
    } else {
      System.err.println("The first argument must be either encrypt or decrypt, got: " + mode);


  private EnvelopeAeadExample() {}

What's next