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:
- A key URI pointing to your KEK.
- Credentials to use the KEK.
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.
Python
Java
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); System.err.println( "Usage: java EnvelopeAeadExample encrypt/decrypt kek-uri gcp-credential-file" + " input-file output-file [associated-data]"); System.exit(1); } 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 AeadConfig.register(); // 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); System.exit(1); } // Create envelope AEAD primitive using AES256 GCM for encrypting the data Aead aead = null; try { KeysetHandle handle = KeysetHandle.generateNew( KmsEnvelopeAeadKeyManager.createKeyTemplate(kekUri, KeyTemplates.get("AES256_GCM"))); aead = handle.getPrimitive(Aead.class); } catch (GeneralSecurityException ex) { System.err.println("Error creating primitive: %s " + ex); System.exit(1); } // Use the primitive to encrypt/decrypt files. if (MODE_ENCRYPT.equals(mode)) { byte[] ciphertext = aead.encrypt(input, associatedData); try (FileOutputStream stream = new FileOutputStream(outputFile)) { stream.write(ciphertext); } } else if (MODE_DECRYPT.equals(mode)) { byte[] plaintext = aead.decrypt(input, associatedData); try (FileOutputStream stream = new FileOutputStream(outputFile)) { stream.write(plaintext); } } else { System.err.println("The first argument must be either encrypt or decrypt, got: " + mode); System.exit(1); } System.exit(0); } private EnvelopeAeadExample() {} }
What's next
See more examples of using client-side encryption to encrypt your data before adding it to a Cloud SQL database.
Learn more about using Client-side encryption with Tink and Cloud KMS to encrypt data before uploading it to Google Cloud Storage.